Bagikan melalui


Gambaran umum konvensi X64 ABI

Topik ini menjelaskan antarmuka biner aplikasi dasar (ABI) untuk x64, ekstensi 64-bit ke arsitektur x86. Ini mencakup topik seperti konvensi panggilan, tata letak jenis, tumpukan dan daftarkan penggunaan, dan banyak lagi.

Konvensi panggilan x64

Dua perbedaan penting antara x86 dan x64 adalah:

  • Kemampuan pengalamatan 64-bit
  • Enam belas 64-bit mendaftar untuk penggunaan umum.

Mengingat kumpulan register yang diperluas, x64 menggunakan konvensi panggilan __fastcall dan model penanganan pengecualian berbasis RISC.

Konvensi menggunakan __fastcall register untuk empat argumen pertama, dan bingkai tumpukan untuk meneruskan lebih banyak argumen. Untuk detail tentang konvensi panggilan x64, termasuk penggunaan register, parameter tumpukan, nilai pengembalian, dan unwinding tumpukan, lihat konvensi panggilan x64.

Untuk informasi selengkapnya tentang __vectorcall konvensi panggilan, lihat __vectorcall.

Mengaktifkan pengoptimalan kompilator x64

Opsi pengkompilasi berikut membantu Anda mengoptimalkan aplikasi untuk x64:

Jenis x64 dan tata letak penyimpanan

Bagian ini menjelaskan penyimpanan jenis data untuk arsitektur x64.

Jenis skalar

Meskipun dimungkinkan untuk mengakses data dengan penyelarasan apa pun, menyelaraskan data pada batas alaminya, atau kelipatan batas alaminya, untuk menghindari kehilangan performa. Enum adalah bilangan bulat konstan dan diperlakukan sebagai bilangan bulat 32-bit. Tabel berikut ini menjelaskan definisi jenis dan penyimpanan yang direkomendasikan untuk data karena berkaitan dengan perataan menggunakan nilai perataan berikut:

  • Byte - 8 bit
  • Word - 16 bit
  • Kata ganda - 32 bit
  • Quadword - 64 bit
  • Oktaword - 128 bit
Jenis skalar Jenis data C Ukuran penyimpanan (dalam byte) Perataan yang direkomendasikan
INT8 char 1 Byte
UINT8 unsigned char 1 Byte
INT16 short 2 Word
UINT16 unsigned short 2 Word
INT32 int, long 4 Kata ganda
UINT32 unsigned int, unsigned long 4 Kata ganda
INT64 __int64 8 Quadword
UINT64 unsigned __int64 8 Quadword
FP32 (presisi tunggal) float 4 Kata ganda
FP64 (presisi ganda) double 8 Quadword
POINTER * 8 Quadword
__m64 struct __m64 8 Quadword
__m128 struct __m128 16 Oktaword

Tata letak agregat dan gabungan x64

Jenis lain, seperti array, struktur, dan serikat, memiliki persyaratan penyelarasan yang lebih ketat yang memastikan penyimpanan agregat dan gabungan dan pengambilan data yang konsisten. Berikut adalah definisi untuk array, struktur, dan union:

  • Array

    Berisi sekelompok objek data yang berdekatan yang diurutkan. Setiap objek disebut elemen. Semua elemen dalam array memiliki ukuran dan jenis data yang sama.

  • Struktur

    Berisi sekelompok objek data yang diurutkan. Tidak seperti elemen array, anggota struktur dapat memiliki jenis dan ukuran data yang berbeda.

  • Union

    Objek yang menyimpan salah satu dari sekumpulan anggota bernama. Anggota set bernama bisa dari jenis apa pun. Penyimpanan yang dialokasikan untuk gabungan sama dengan penyimpanan yang diperlukan untuk anggota terbesar dari serikat tersebut, ditambah padding apa pun yang diperlukan untuk penyelarasan.

Tabel berikut menunjukkan perataan yang sangat direkomendasikan untuk anggota skalar serikat dan struktur.

Jenis Skalar Tipe Data C Perataan yang Diperlukan
INT8 char Byte
UINT8 unsigned char Byte
INT16 short Word
UINT16 unsigned short Word
INT32 int, long Kata ganda
UINT32 unsigned int, unsigned long Kata ganda
INT64 __int64 Quadword
UINT64 unsigned __int64 Quadword
FP32 (presisi tunggal) float Kata ganda
FP64 (presisi ganda) double Quadword
POINTER * Quadword
__m64 struct __m64 Quadword
__m128 struct __m128 Oktaword

Aturan perataan agregat berikut ini berlaku:

  • Perataan array sama dengan perataan salah satu elemen array.

  • Perataan awal struktur atau serikat adalah perataan maksimum setiap anggota individu. Setiap anggota dalam struktur atau serikat harus ditempatkan pada penyelarasan yang tepat seperti yang didefinisikan dalam tabel sebelumnya, yang mungkin memerlukan padding internal implisit, tergantung pada anggota sebelumnya.

  • Ukuran struktur harus merupakan kelipatan integral dari perataannya, yang mungkin memerlukan padding setelah anggota terakhir. Karena struktur dan penyatuan dapat dikelompokkan dalam array, setiap elemen array dari struktur atau gabungan harus dimulai dan berakhir pada perataan yang tepat yang ditentukan sebelumnya.

  • Dimungkinkan untuk menyelaraskan data sedih agar lebih besar dari persyaratan penyelarasan selama aturan sebelumnya dipertahankan.

  • Pengkompilasi individu dapat menyesuaikan pengemasan struktur karena alasan ukuran. Misalnya, /Zp (Struct Member Alignment) memungkinkan untuk menyesuaikan pengemasan struktur.

Contoh perataan struktur x64

Empat contoh berikut masing-masing mendeklarasikan struktur atau serikat yang selaras, dan gambar yang sesuai menggambarkan tata letak struktur atau penyatuan tersebut dalam memori. Setiap kolom dalam gambar mewakili byte memori, dan angka dalam kolom menunjukkan perpindahan byte tersebut. Nama di baris kedua dari setiap gambar sesuai dengan nama variabel dalam deklarasi. Kolom berbayang menunjukkan padding yang diperlukan untuk mencapai perataan yang ditentukan.

Contoh 1

// Total size = 2 bytes, alignment = 2 bytes (word).

_declspec(align(2)) struct {
    short a;      // +0; size = 2 bytes
}

Diagram memperlihatkan contoh 1 tata letak struktur.

Contoh 2

// Total size = 24 bytes, alignment = 8 bytes (quadword).

_declspec(align(8)) struct {
    int a;       // +0; size = 4 bytes
    double b;    // +8; size = 8 bytes
    short c;     // +16; size = 2 bytes
}

Diagram memperlihatkan contoh 2 tata letak struktur.

Contoh 3

// Total size = 12 bytes, alignment = 4 bytes (doubleword).

_declspec(align(4)) struct {
    char a;       // +0; size = 1 byte
    short b;      // +2; size = 2 bytes
    char c;       // +4; size = 1 byte
    int d;        // +8; size = 4 bytes
}

Diagram memperlihatkan contoh 3 tata letak struktur.

Contoh 4

// Total size = 8 bytes, alignment = 8 bytes (quadword).

_declspec(align(8)) union {
    char *p;      // +0; size = 8 bytes
    short s;      // +0; size = 2 bytes
    long l;       // +0; size = 4 bytes
}

Diagram memperlihatkan contoh 4 tata letak union.

Bitfields

Bidang bit struktur dibatasi hingga 64 bit dan dapat berjenis int yang ditandatangani, int tidak ditandatangani, int64, atau int64 yang tidak ditandatangani. Bidang bit yang melewati batas jenis akan melewati bit untuk menyelaraskan bitfield ke perataan jenis berikutnya. Misalnya, bitfield bilangan bulat mungkin tidak melewati batas 32-bit.

Konflik dengan pengkompilasi x86

Jenis data yang lebih besar dari 4 byte tidak secara otomatis diratakan pada tumpukan saat Anda menggunakan kompilator x86 untuk mengkompilasi aplikasi. Karena arsitektur untuk pengkompilasi x86 adalah tumpukan selaras 4 byte, apa pun yang lebih besar dari 4 byte, misalnya, bilangan bulat 64-bit, tidak dapat secara otomatis diselaraskan ke alamat 8-byte.

Bekerja dengan data yang tidak ditandatangani memiliki dua implikasi.

  • Mungkin perlu waktu lebih lama untuk mengakses lokasi yang tidak sejajar daripada yang diperlukan untuk mengakses lokasi yang selaras.

  • Lokasi yang tidak ditandatangani tidak dapat digunakan dalam operasi yang saling mengunci.

Jika Anda memerlukan perataan yang lebih ketat, gunakan __declspec(align(N)) pada deklarasi variabel Anda. Ini menyebabkan pengkompilasi secara dinamis menyelaraskan tumpukan untuk memenuhi spesifikasi Anda. Namun, menyesuaikan tumpukan secara dinamis pada waktu proses dapat menyebabkan eksekusi aplikasi Anda yang lebih lambat.

x64 mendaftarkan penggunaan

Arsitektur x64 menyediakan untuk 16 register tujuan umum (selanjutnya disebut sebagai register bilangan bulat) serta 16 register XMM/YMM yang tersedia untuk penggunaan floating-point. Register volatil adalah register awal yang diduga oleh penelepon untuk dihancurkan melalui panggilan. Register nonvolatile diperlukan untuk mempertahankan nilainya di seluruh panggilan fungsi dan harus disimpan oleh penerima panggilan jika digunakan.

Mendaftarkan volatilitas dan pelestarian

Tabel berikut ini menjelaskan bagaimana setiap register digunakan di seluruh panggilan fungsi:

Daftar Status Menggunakan
RAX Volatile Mengembalikan register nilai
RCX Volatile Argumen bilangan bulat pertama
RDX Volatile Argumen bilangan bulat kedua
R8 Volatile Argumen bilangan bulat ketiga
R9 Volatile Argumen bilangan bulat keempat
R10:R11 Volatile Harus dipertahankan sesuai kebutuhan oleh pemanggil; digunakan dalam instruksi syscall/sysret
R12:R15 Nonvolatile Harus dipertahankan oleh penerima panggilan
RDI Nonvolatile Harus dipertahankan oleh penerima panggilan
RSI Nonvolatile Harus dipertahankan oleh penerima panggilan
RBX Nonvolatile Harus dipertahankan oleh penerima panggilan
RBP Nonvolatile Dapat digunakan sebagai penunjuk bingkai; harus dipertahankan oleh penerima panggilan
RSP Nonvolatile Penunjuk tumpukan
XMM0, YMM0 Volatile Argumen FP pertama; argumen jenis vektor pertama saat __vectorcall digunakan
XMM1, YMM1 Volatile Argumen FP kedua; argumen jenis vektor kedua saat __vectorcall digunakan
XMM2, YMM2 Volatile Argumen FP ketiga; argumen jenis vektor ketiga saat __vectorcall digunakan
XMM3, YMM3 Volatile Argumen FP keempat; argumen tipe vektor keempat saat __vectorcall digunakan
XMM4, YMM4 Volatile Harus dipertahankan sesuai kebutuhan oleh pemanggil; Argumen tipe vektor kelima saat __vectorcall digunakan
XMM5, YMM5 Volatile Harus dipertahankan sesuai kebutuhan oleh pemanggil; argumen jenis vektor keenam saat __vectorcall digunakan
XMM6:XMM15, YMM6:YMM15 Nonvolatile (XMM), Volatil (bagian atas YMM) Harus dipertahankan oleh penerima panggilan. Register YMM harus dipertahankan sesuai kebutuhan oleh pemanggil.

Pada fungsi keluar dan pada entri fungsi ke panggilan Pustaka Runtime C dan panggilan sistem Windows, bendera arah dalam daftar bendera CPU diharapkan dihapus.

Penggunaan tumpukan

Untuk detail tentang alokasi tumpukan, perataan, jenis fungsi, dan bingkai tumpukan pada x64, lihat penggunaan tumpukan x64.

Prolog dan epilog

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, dan epilog di setiap keluar ke fungsi. Untuk detail tentang kode prolog dan epilog yang diperlukan pada x64, lihat prolog x64 dan epilog.

Penanganan pengecualian x64

Untuk informasi tentang konvensi dan struktur data yang digunakan untuk menerapkan penanganan pengecualian terstruktur dan perilaku penanganan pengecualian C++ pada x64, lihat penanganan pengecualian x64.

Rakitan intrinsik dan sebaris

Salah satu batasan untuk kompiler x64 adalah tidak ada dukungan perakitan sebaris. Ini berarti bahwa fungsi yang tidak dapat ditulis dalam C atau C++ harus ditulis sebagai subroutine atau sebagai fungsi intrinsik yang didukung oleh pengkompilasi. Fungsi tertentu sensitif terhadap performa sementara fungsi lain tidak. Fungsi sensitif performa harus diimplementasikan sebagai fungsi intrinsik.

Intrinsik yang didukung oleh kompilator dijelaskan dalam intrinsik Compiler.

Format gambar x64

Format gambar x64 yang dapat dieksekusi adalah PE32+. Gambar yang dapat dieksekusi (DLL dan EXE) dibatasi hingga ukuran maksimum 2 gigabyte, sehingga alamat relatif dengan perpindahan 32-bit dapat digunakan untuk mengatasi data gambar statis. Data ini mencakup tabel alamat impor, konstanta string, data global statis, dan sebagainya.

Lihat juga

Konvensi Panggilan