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ünde bulundurulduğunda x64, __fastcall çağırma kuralını ve RISC tabanlı özel durum işleme modelini kullanır.
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 __vectorcall
daha fazla bilgi için 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. Numaralandırmalar 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:
- Bayt - 8 bit
- Word - 16 bit
- Çift kelime - 32 bit
- Dörtlü - 64 bit
- Octaword - 128 bit
Skaler tür | C veri türü | Depolama boyutu (bayt cinsinden) | Önerilen hizalama |
---|---|---|---|
INT8 |
char |
1 | Bayt |
UINT8 |
unsigned char |
1 | Bayt |
INT16 |
short |
2 | Word |
UINT16 |
unsigned short |
2 | Word |
INT32 |
int , long |
4 | Çift kelime |
UINT32 |
unsigned int , unsigned long |
4 | Çift kelime |
INT64 |
__int64 |
8 | Dörtlü |
UINT64 |
unsigned __int64 |
8 | Dörtlü |
FP32 (tek duyarlıklı) |
float |
4 | Çift kelime |
FP64 (çift duyarlık) |
double |
8 | Dörtlü |
POINTER |
* | 8 | Dörtlü |
__m64 |
struct __m64 |
8 | Dörtlü |
__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, bu birleşimin en büyük üyesi için gereken depolama alanına ve hizalama için gereken doldurmaya eşittir.
Aşağıdaki tabloda, birleşimlerin ve yapıların skaler üyeleri için kesinlikle önerilen hizalama gösterilmektedir.
Skaler Tür | C Veri Türü | Gerekli Hizalama |
---|---|---|
INT8 |
char |
Bayt |
UINT8 |
unsigned char |
Bayt |
INT16 |
short |
Word |
UINT16 |
unsigned short |
Word |
INT32 |
int , long |
Çift kelime |
UINT32 |
unsigned int , unsigned long |
Çift kelime |
INT64 |
__int64 |
Dörtlü |
UINT64 |
unsigned __int64 |
Dörtlü |
FP32 (tek duyarlıklı) |
float |
Çift kelime |
FP64 (çift duyarlık) |
double |
Dörtlü |
POINTER |
* | Dörtlü |
__m64 |
struct __m64 |
Dörtlü |
__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 örtük iç doldurma gerektirebilir.
Yapı boyutu, hizalamasının tam sayı katı olmalıdır ve 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
}
Ö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
}
Ö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
}
Ö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
}
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 hizalamasına hizalamak 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 aramada yok edildiği varsayılan karalama 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 | Kullanma |
---|---|---|
RAX | Uçucu | Dönüş değeri yazmaç |
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ü tamsayı bağımsız değişkeni |
R10:R11 | Uçucu | Arayan tarafından gerektiği gibi korunmalıdır; syscall/sysret yönergelerinde kullanılır |
R12:R15 | Kalıcı | Çağıran tarafından korunmalıdır |
RDI | Kalıcı | Çağıran tarafından korunmalıdır |
RSI | Kalıcı | Çağıran tarafından korunmalıdır |
RBX | Kalıcı | Çağıran tarafından korunmalıdır |
RBP | Kalıcı | Çerçeve işaretçisi olarak kullanılabilir; callee tarafından korunmalıdır |
RSP | Kalıcı | Yığın işaretçisi |
XMM0, YMM0 | Uçucu | İlk FP bağımsız değişkeni; kullanıldığında ilk vektör türü bağımsız değişkeni __vectorcall |
XMM1, YMM1 | Uçucu | İkinci FP bağımsız değişkeni; kullanıldığında ikinci vektör türü bağımsız değişkeni __vectorcall |
XMM2, YMM2 | Uçucu | Üçüncü FP bağımsız değişkeni; kullanıldığında üçüncü vektör türü bağımsız değişkeni __vectorcall |
XMM3, YMM3 | Uçucu | Dördüncü FP bağımsız değişkeni; kullanıldığında dördüncü vektör türü bağımsız değişkeni __vectorcall |
XMM4, YMM4 | Uçucu | Arayan tarafından gerektiği gibi korunmalıdır; kullanıldığında beşinci vektör türü bağımsız değişkeni __vectorcall |
XMM5, YMM5 | Uçucu | Arayan tarafından gerektiği gibi korunmalıdır; kullanıldığında altıncı vektör türü bağımsız değişkeni __vectorcall |
XMM6:XMM15, YMM6:YMM15 | Geçici Olmayan (XMM), Geçici (YMM'nin üst yarısı) | Callee tarafından korunmalıdır. YMM kayıtları arayan tarafından gerektiği gibi korunmalıdır. |
İş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 prologu ve bir işleve yapılan her çıkışta kapsamları olmalıdır. x64'te gerekli giriş ve kapsam koduyla ilgili ayrıntılar için bkz . x64 giriş ve bitiş.
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.
İç ve satır içi bütünleştirilmiş kod
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.