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 simpulDorong 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 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 tidak diskalakan dicatat dalam dua slot berikutnya dalam format little-endian, memungkinkan alokasi hingga 4GB - 8.
UWOP_ALLOC_SMALL
(2) 1 simpulAlokasikan 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 = 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 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 simpulSimpan 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 simpulSimpan 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 simpulSimpan 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 simpulSimpan 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 simpulDorong 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 ROBEK 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 ROBEK 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:Alamat pengembalian POP RIP dari atas tumpukan ke dalam Temp
Dorong SS
Dorong RSP lama
Dorong EFLAGS
Dorong CS
Dorong Temp
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:
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 langsung mengatasi penunjuk pengembalian. 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 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.
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 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))