Aracılığıyla paylaş


x64 ABI kurallarına genel bakış

Bu konu, x86 mimarisinin 64 bit uzantısı olan x64 için temel uygulama ikili arabirimini (ABI) açıklar. Çağrı kuralı, tür düzeni, yığın ve kayıt kullanımı gibi konuları ve daha fazlasını kapsar.

x64 çağrı kuralları

x86 ile x64 arasındaki iki önemli fark şunlardır:

  • 64 bit adresleme özelliği
  • Genel kullanım için on altı 64 bit yazmaç.

Genişletilmiş yazmaç kümesi göz önüne alındığında, x64 çağrı kuralını ve RISC tabanlı özel durum işleme modelini kullanır __fastcall .

Kural, __fastcall ilk dört bağımsız değişken için yazmaçları ve daha fazla bağımsız değişken geçirmek için yığın çerçevesini kullanır. Kayıt kullanımı, yığın parametreleri, dönüş değerleri ve yığın geri sarma gibi x64 çağrı kuralıyla ilgili ayrıntılar için bkz . x64 çağırma kuralı.

Çağırma kuralı hakkında daha fazla bilgi için __vectorcall bkz __vectorcall.

x64 derleyici iyileştirmesini etkinleştirme

Aşağıdaki derleyici seçeneği uygulamanızı x64 için iyileştirmenize yardımcı olur:

x64 türü ve depolama düzeni

Bu bölümde x64 mimarisi için veri türlerinin depolanması açıklanmaktadır.

Skaler türler

Herhangi bir hizalamayla verilere erişmek mümkün olsa da, performans kaybını önlemek için verileri doğal sınırına veya doğal sınırının bir katına hizalayın. Enum'lar sabit tamsayılardır ve 32 bit tamsayılar olarak değerlendirilir. Aşağıdaki tabloda, aşağıdaki hizalama değerlerini kullanarak hizalamayla ilgili olarak tür tanımı ve veriler için önerilen depolama açıklanmaktadır:

  • Byte - 8 bit
  • Word - 16 bit
  • Çift kelime - 32 bit
  • Quadword - 64 bit
  • Octaword - 128 bit
Skalar tür C veri türü Depolama boyutu (bayt cinsinden) Önerilen hizalama
INT8 char 1 Bayt
UINT8 unsigned char 1 Bayt
INT16 short 2 Kelime
UINT16 unsigned short 2 Kelime
INT32 int, long 4 Çift kelime
UINT32 unsigned int, unsigned long 4 Çift kelime
INT64 __int64 8 64 bitlik kelime
UINT64 unsigned __int64 8 64 bitlik kelime
FP32 (tek duyarlıklı) float 4 Çift kelime
FP64 (çift duyarlık) double 8 64 bitlik kelime
POINTER * 8 64 bitlik kelime
__m64 struct __m64 8 64 bitlik kelime
__m128 struct __m128 16 Octaword

x64 toplama ve birleşim düzeni

Diziler, yapılar ve birleşimler gibi diğer türlerin tutarlı toplama ve birleşim depolama ve veri alımını sağlayan daha katı hizalama gereksinimleri vardır. Dizi, yapı ve birleşim tanımları şunlardır:

  • Dizi

    Bitişik veri nesnelerinden oluşan sıralı bir grup içerir. Her nesne bir öğe olarak adlandırılır. Dizideki tüm öğeler aynı boyuta ve veri türüne sahiptir.

  • Yapı

    Sıralı bir veri nesnesi grubu içerir. Bir dizinin öğelerinden farklı olarak, bir yapının üyeleri farklı veri türlerine ve boyutlarına sahip olabilir.

  • Birleşim

    Adlandırılmış üye kümesinden herhangi birini tutan nesne. Adlandırılmış kümenin üyeleri herhangi bir türde olabilir. Birleşim için ayrılan depolama, birleşimin en büyük üyesinin gerektirdiği depolama alanına ve hizalama için gereken dolguya eşittir.

Aşağıdaki tabloda, birleşimlerin ve yapıların skaler üyeleri için kesinlikle önerilen hizalama gösterilmektedir.

Skaler Tip C Veri Türü Gerekli Hizalama
INT8 char Bayt
UINT8 unsigned char Bayt
INT16 short Kelime
UINT16 unsigned short Kelime
INT32 int, long Çift kelime
UINT32 unsigned int, unsigned long Çift kelime
INT64 __int64 64 bitlik kelime
UINT64 unsigned __int64 64 bitlik kelime
FP32 (tek duyarlıklı) float Çift kelime
FP64 (çift duyarlık) double 64 bitlik kelime
POINTER * 64 bitlik kelime
__m64 struct __m64 64 bitlik kelime
__m128 struct __m128 Octaword

Aşağıdaki toplama hizalama kuralları geçerlidir:

  • Dizinin hizalaması, dizinin öğelerinden birinin hizalaması ile aynıdır.

  • Bir yapının veya birleşimin başlangıcının hizalaması, herhangi bir üyenin en yüksek hizalamasıdır. Yapı veya birleşim içindeki her üye, önceki tabloda tanımlandığı gibi uygun hizalamaya yerleştirilmelidir. Bu, önceki üyeye bağlı olarak otomatik iç doldurma gerektirebilir.

  • Yapının boyutu, hizalamasının tam katı olmalıdır; bu da son üyeden sonra doldurma gerektirebilir. Yapılar ve birleşimler diziler halinde gruplandırılabildiğinden, bir yapı veya birleşimin her dizi öğesi daha önce belirlenen uygun hizalamada başlamalıdır ve bitmelidir.

  • Önceki kurallar korunduktan sonra verileri hizalama gereksinimlerinden daha büyük olacak şekilde hizalamak mümkündür.

  • Tek bir derleyici, boyut nedenleriyle bir yapının ambalajını ayarlayabilir. Örneğin, /Zp (Yapı Üyesi Hizalaması), yapıların ambalajının ayarlanmasını sağlar.

x64 yapı hizalama örnekleri

Aşağıdaki dört örnekte her biri hizalanmış bir yapı veya birleşim bildirilir ve buna karşılık gelen şekiller bu yapının veya birleşimin bellekteki düzenini gösterir. Şekildeki her sütun bir bellek baytını temsil eder ve sütundaki sayı bu bayt yer değiştirmesini gösterir. Her şeklin ikinci satırındaki ad, bildirimdeki bir değişkenin adına karşılık gelir. Gölgeli sütunlar, belirtilen hizalamayı elde etmek için gereken doldurmayı gösterir.

Örnek 1

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

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

1 gibi yapı düzenini gösteren diyagram. Diyagramda 2 bayt bellek gösterilir. Üye a, kısa, 0 ile 1 arasındaki baytları kaplar.

Örnek 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
}

Örneğin 2 yapı düzenini gösteren diyagram.

Diyagramda 24 bayt bellek gösterilir. Üye a, bir int, 0 ile 3 arasındaki baytları kaplar. Diyagram, 4'ten 7'ye kadar olan baytlarda dolgu işlemini göstermektedir. Üye b, bir çift, 8 ile 15 arasında baytları kaplar. Üye c, kısa bir veri tipi olan, 16 ile 17 arasındaki baytları kaplamaktadır. 18 ile 23 arasında bayt kullanılmaz.

Örnek 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
}

Örneğin 3 yapı düzenini gösteren diyagram.

Diyagramda 12 bayt bellek gösterilir. Üye a, bir char, bayt 0 kaplar. Bayt 1 dolgudur. Kısa bir üye olan b, 2 ile 4 arasındaki baytları kaplar. Üye c, bir char, 4. baytı kaplar. 5 ile 7 numaralı baytlar dolgudur. Üye d, bir int, 8 ile 11 arasındaki baytları kaplar.

Örnek 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
}

Birleşim düzenini gösteren diyagram, örneğin 4.

Diyagramda 8 bayt bellek gösterilir. Üye p, bir char, bayt 0'ı kaplar. Üye s, kısa, 0 ile 1 arasındaki baytları kaplar. Üye l, bir long tipi olarak, 0 ile 3 arasındaki baytları kaplar. 4'ten 7'ye kadar olan baytlar doldurmadır.

Bit Alanları

Yapı biti alanları 64 bit ile sınırlıdır ve imzalanmamış int, unsigned int, int64 veya unsigned int64 türünde olabilir. Tür sınırını geçen bit alanları, bit alanını bir sonraki tür hizasına uyumlu hale getirmek için bitleri atlar. Örneğin, tamsayı bit alanları 32 bit sınırı geçmeyebilir.

x86 derleyicisiyle çakışmalar

4 bayttan büyük veri türleri, bir uygulamayı derlemek için x86 derleyicisini kullandığınızda yığına otomatik olarak hizalanmamıştır. x86 derleyicisinin mimarisi 4 bayt hizalanmış bir yığın olduğundan, 4 bayttan büyük olan her şey (örneğin, 64 bitlik bir tamsayı) otomatik olarak 8 baytlık bir adrese hizalanamaz.

Hizalanmamış verilerle çalışmanın iki etkisi vardır.

  • Hizalanmamış konumlara erişmek, hizalanmış konumlara erişmek için gerekenden daha uzun sürebilir.

  • Hizalanmamış konumlar birbirine kenetlenmiş işlemlerde kullanılamaz.

Daha katı bir hizalamaya ihtiyacınız varsa değişken bildirimlerinizde kullanın __declspec(align(N)) . Bu, derleyicinin yığını belirtimlerinize uyacak şekilde dinamik olarak hizalamasına neden olur. Ancak, yığının çalışma zamanında dinamik olarak ayarlanması uygulamanızın daha yavaş yürütülmesine neden olabilir.

x64 yazmaç kullanımı

x64 mimarisi, 16 genel amaçlı yazmaç (bundan sonra tamsayı yazmaçları olarak adlandırılır) ve kayan nokta kullanımı için 16 XMM/YMM yazmacı sağlar. Geçici yazmaçlar, arayan tarafından bir çağrı sonrasında yok edildikleri varsayılan geçici kullanım yazmaçlarıdır. Geçici olmayan yazmaçlar, bir işlev çağrısında değerlerini korumak için gereklidir ve kullanılırsa çağıran tarafından kaydedilmelidir.

Volatilite ve korumayı kaydetme

Aşağıdaki tabloda, her yazmaç işlevinin işlev çağrıları arasında nasıl kullanıldığı açıklanmaktadır:

Kaydol Durum Kullan
RAX Uçucu Dönüş değeri kaydı
RCX Uçucu İlk tamsayı bağımsız değişkeni
RDX Uçucu İkinci tamsayı bağımsız değişkeni
R8 Uçucu Üçüncü tamsayı bağımsız değişkeni
R9 Uçucu Dördüncü tam sayı argümanı
R10:R11 Uçucu Arayan tarafından gerektiği şekilde korunmalıdır; syscall/sysret yönergelerinde kullanılır
R12:R15 Uçucu olmayan Çağıran tarafından korunmalıdır
RDI Uçucu olmayan Çağıran tarafından korunmalıdır
RSI Uçucu olmayan Çağıran tarafından korunmalıdır
RBX Uçucu olmayan Çağıran tarafından korunmalıdır
RBP Uçucu olmayan Çerçeve işaretçisi olarak kullanılabilir; callee tarafından korunmalıdır
RSP Uçucu olmayan Yığın işaretçisi
XMM0, YMM0 Uçucu İlk FP bağımsız değişkeni; __vectorcall kullanıldığında ilk vektör türü bağımsız değişkeni
XMM1, YMM1 Uçucu İkinci FP bağımsız değişkeni; "__vectorcall" kullanıldığında ikinci vektör türü bağımsız değişkeni
XMM2, YMM2 Uçucu Üçüncü FP bağımsız değişkeni; __vectorcall kullanıldığında üçüncü vektör türü bağımsız değişkeni
XMM3, YMM3 Uçucu Dördüncü FP bağımsız değişkeni; __vectorcall kullanıldığında dördüncü vektör tipi bağımsız değişkeni
XMM4, YMM4 Uçucu Arayan tarafından gerektiği gibi korunmalıdır; __vectorcall kullanıldığında beşinci vektör-tipi argüman olan bağımsız değişken.
XMM5, YMM5 Uçucu Arayan tarafından gerektiği gibi korunmalıdır; __vectorcall kullanıldığında altıncı vektör türü bağımsız değişkeni.
XMM6:XMM15, YMM6:YMM15 Geçici Olmayan (XMM), Geçici (YMM'nin üst yarısı) Callee tarafından korunmalıdır. YMM kayıtlarının, arayanın ihtiyaçlarına göre korunması gerekmektedir.

İşlev çıkışında ve C Çalışma Zamanı Kitaplığı çağrılarına ve Windows sistem çağrılarına işlev girişinde, CPU bayrakları yazmaçlarındaki yön bayrağının temizlenmesi beklenir.

Yığın kullanımı

x64'te yığın ayırma, hizalama, işlev türleri ve yığın çerçeveleri hakkında ayrıntılı bilgi için bkz. x64 yığın kullanımı.

Prolog ve epilog

Yığın alanı ayıran, diğer işlevleri çağıran, geçici olmayan yazmaçları kaydeden veya özel durum işlemeyi kullanan her işlevin, adres sınırları ilgili işlev tablosu girişiyle ilişkili geri sarma verilerinde açıklanan bir başlangıcı ve işleve yapılan her çıkışta bir bitimi olmalıdır. Gerekli x64 prolog ve epilog kodu ile ilgili ayrıntılar için bkz x64 prolog ve epilog.

x64 özel durum işleme

x64 üzerinde yapılandırılmış özel durum işleme ve C++ özel durum işleme davranışını uygulamak için kullanılan kurallar ve veri yapıları hakkında bilgi için bkz . x64 özel durum işleme.

Makine diline özgü fonksiyonlar ve satır içi montaj dili

x64 derleyicisinin kısıtlamalarından biri satır içi derleyici desteği değildir. Bu, C veya C++ dilinde yazılamayacak işlevlerin alt yordam olarak veya derleyici tarafından desteklenen iç işlevler olarak yazılması gerekeceği anlamına gelir. Bazı işlevler performansa duyarlıyken diğerleri duyarlı değildir. Performansa duyarlı işlevler iç işlevler olarak uygulanmalıdır.

Derleyici tarafından desteklenen iç öğeler Derleyici iç bilgileri bölümünde açıklanmıştır.

x64 resim biçimi

x64 yürütülebilir görüntü biçimi PE32+. Yürütülebilir görüntüler (hem DLL'ler hem de EXE'ler) en fazla 2 gigabayt boyutuyla sınırlıdır, bu nedenle statik görüntü verilerini ele almak için 32 bit yer değiştirme ile göreli adresleme kullanılabilir. Bu veriler içeri aktarma adresi tablosunu, dize sabitlerini, statik genel verileri vb. içerir.

Ayrıca bkz.

Çağırma Kuralları