Bagikan melalui


Prolog dan epilog x64

Setiap fungsi yang mengalokasikan ruang tumpukan, memanggil fungsi lain, menyimpan register nonvolatile, atau menggunakan penanganan pengecualian harus memiliki prolog yang batas alamatnya dijelaskan dalam data unwind yang terkait dengan entri tabel fungsi masing-masing. Untuk informasi selengkapnya, lihat penanganan pengecualian x64. Prolog menyimpan register argumen di alamat rumah mereka jika perlu, mendorong register nonvolatile pada tumpukan, mengalokasikan bagian tetap dari tumpukan untuk lokal dan sementara, dan secara opsional membuat penunjuk bingkai. Data unwind terkait harus menjelaskan tindakan prolog dan harus memberikan informasi yang diperlukan untuk membatalkan efek kode prolog.

Jika alokasi tetap dalam tumpukan lebih dari satu halaman (yaitu, lebih besar dari 4096 byte), ada kemungkinan bahwa alokasi tumpukan dapat mencakup lebih dari satu halaman memori virtual dan, oleh karena itu, alokasi harus diperiksa sebelum dialokasikan. Rutinitas khusus yang dapat dipanggil dari prolog dan yang tidak menghancurkan salah satu register argumen disediakan untuk tujuan ini.

Metode yang disukai untuk menyimpan register nonvolatile adalah memindahkannya ke tumpukan sebelum alokasi tumpukan tetap. Jika alokasi tumpukan tetap dilakukan sebelum register nonvolatile disimpan, maka kemungkinan besar perpindahan 32-bit diperlukan untuk mengatasi area register yang disimpan. (Dilaporkan, dorongan register secepat bergerak dan harus tetap demikian untuk masa depan yang dapat diperkirakan terlepas dari dependensi tersirat antara dorongan.) Register nonvolatile dapat disimpan dalam urutan apa pun. Namun, penggunaan pertama register nonvolatile dalam prolog harus untuk menyimpannya.

Kode prolog

Kode untuk prolog khas mungkin:

    mov    [RSP + 8], RCX
    push   R15
    push   R14
    push   R13
    sub    RSP, fixed-allocation-size
    lea    R13, 128[RSP]
    ...

Prolog ini menyimpan argumen register RCX di lokasi asalnya, menyimpan register nonvolatile R13-R15, mengalokasikan bagian tetap dari bingkai tumpukan, dan menetapkan penunjuk bingkai yang menunjuk 128 byte ke area alokasi tetap. Menggunakan offset memungkinkan lebih banyak area alokasi tetap untuk ditangani dengan offset satu byte.

Jika ukuran alokasi tetap lebih besar dari atau sama dengan satu halaman memori, maka fungsi pembantu harus dipanggil sebelum memodifikasi RSP. Pembantu ini, __chkstk, memeriksa rentang tumpukan yang akan dialokasikan untuk memastikan bahwa tumpukan diperluas dengan benar. Dalam hal ini, contoh prolog sebelumnya adalah:

    mov    [RSP + 8], RCX
    push   R15
    push   R14
    push   R13
    mov    RAX,  fixed-allocation-size
    call   __chkstk
    sub    RSP, RAX
    lea    R13, 128[RSP]
    ...

Pembantu __chkstk tidak akan memodifikasi register apa pun selain R10, R11, dan kode kondisi. Secara khusus, ini akan mengembalikan RAX yang tidak berubah dan membiarkan semua register nonvolatile dan register argument-passing tidak dimodifikasi.

Kode epilog

Kode Epilog ada di setiap pintu keluar ke fungsi. Padahal biasanya hanya ada satu prolog, mungkin ada banyak epilog. Kode Epilog memangkas tumpukan ke ukuran alokasi tetapnya (jika perlu), membatalkan alokasi tumpukan tetap, memulihkan register nonvolatile dengan memunculkan nilai yang disimpan dari tumpukan, dan mengembalikan.

Kode epilog harus mengikuti serangkaian aturan yang ketat agar kode unwind dapat dilepaskan dengan andal melalui pengecualian dan interupsi. Aturan ini mengurangi jumlah data unwind yang diperlukan, karena tidak ada data tambahan yang diperlukan untuk menjelaskan setiap epilog. Sebaliknya, kode unwind dapat menentukan bahwa epilog sedang dijalankan dengan memindai maju melalui aliran kode untuk mengidentifikasi epilog.

Jika tidak ada penunjuk bingkai yang digunakan dalam fungsi, maka epilog harus terlebih dahulu membatalkan alokasi bagian tetap dari tumpukan, register nonvolatile muncul, dan kontrol dikembalikan ke fungsi panggilan. Contohnya,

    add      RSP, fixed-allocation-size
    pop      R13
    pop      R14
    pop      R15
    ret

Jika penunjuk bingkai digunakan dalam fungsi, tumpukan harus dipangkas ke alokasi tetapnya sebelum eksekusi epilog. Tindakan ini secara teknis bukan bagian dari epilog. Misalnya, epilog berikut dapat digunakan untuk membatalkan prolog yang sebelumnya digunakan:

    lea      RSP, -128[R13]
    ; epilogue proper starts here
    add      RSP, fixed-allocation-size
    pop      R13
    pop      R14
    pop      R15
    ret

Dalam praktiknya, ketika penunjuk bingkai digunakan, tidak ada alasan yang baik untuk menyesuaikan RSP dalam dua langkah, sehingga epilog berikut akan digunakan sebagai gantinya:

    lea      RSP, fixed-allocation-size - 128[R13]
    pop      R13
    pop      R14
    pop      R15
    ret

Formulir-formulir ini adalah satu-satunya yang legal untuk epilog. Ini harus terdiri add RSP,constant dari atau lea RSP,constant[FPReg], diikuti oleh serangkaian pop register nol atau lebih 8-byte dan return atau jmp. (Hanya subset jmp pernyataan yang diizinkan dalam epilog. Subset secara eksklusif adalah kelas jmp pernyataan dengan referensi memori ModRM di mana nilai bidang mod MODRM adalah 00. Penggunaan jmp pernyataan dalam epilog dengan nilai bidang modRM 01 atau 10 dilarang. Lihat Tabel A-15 dalam Manual Volume 3 Programmer Arsitektur AMD x86-64: Tujuan Umum dan Instruksi Sistem, untuk informasi selengkapnya tentang referensi ModRM yang diizinkan.) Tidak ada kode lain yang dapat muncul. Secara khusus, tidak ada yang dapat dijadwalkan dalam epilog, termasuk pemuatan nilai yang dikembalikan.

Ketika penunjuk bingkai tidak digunakan, epilog harus digunakan add RSP,constant untuk membatalkan alokasi bagian tetap dari tumpukan. Ini mungkin tidak menggunakan lea RSP,constant[RSP] sebagai gantinya. Pembatasan ini ada sehingga kode unwind memiliki lebih sedikit pola untuk dikenali saat mencari epilog.

Mengikuti aturan ini memungkinkan kode unwind untuk menentukan bahwa epilog saat ini sedang dijalankan dan untuk mensimulasikan eksekusi sisa epilog untuk memungkinkan pembuatan ulang konteks fungsi panggilan.

Baca juga

Konvensi Perangkat Lunak x64