ARM64 ABI kurallarına genel bakış
ARM işlemcilerinde 64 bit modunda (ARMv8 veya üzeri mimariler) derlendiğinde ve çalıştırıldığında Windows için temel uygulama ikili arabirimi (ABI), çoğunlukla ARM'nin standart AArch64 EABI'sini izler. Bu makalede, EABI'de belgelenen bazı temel varsayımlar ve değişiklikler vurgulanır. 32 bit ABI hakkında bilgi için bkz . ARM ABI kurallarına genel bakış. Standart ARM EABI hakkında daha fazla bilgi için bkz . ARM Mimarisi (dış bağlantı) için Uygulama İkili Arabirimi (ABI).
Tanımlar
64 bit desteğin kullanıma sunulmasıyla BIRLIKTE ARM çeşitli terimler tanımlamıştır:
- AArch32 – Başparmak modu yürütme dahil olmak üzere ARM tarafından tanımlanan eski 32 bit yönerge kümesi mimarisi (ISA).
- AArch64 – ARM tarafından tanımlanan yeni 64 bit yönerge kümesi mimarisi (ISA).
- ARMv7 – Yalnızca AArch32 desteğini içeren "7. nesil" ARM donanımının belirtimi. ARM donanımının bu sürümü, ARM için Windows'un desteklenen ilk sürümüdür.
- ARMv8 – Hem AArch32 hem de AArch64 desteğini içeren "8. nesil" ARM donanımının belirtimi.
Windows şu terimleri de kullanır:
- ARM – 32 bit ARM mimarisini (AArch32) ifade eder ve bazen WoA (ARM üzerinde Windows) olarak da adlandırılır.
- ARM32 , yukarıdaki ARM ile aynıdır; netlik için bu belgede kullanılır.
- ARM64 – 64 bit ARM mimarisini (AArch64) ifade eder. WoA64 diye bir şey yok.
Son olarak, veri türlerine başvururken ARM'den aşağıdaki tanımlara başvurulur:
- Kısa Vektör : Doğrudan SIMD'de temsil edilebilen bir veri türü, 8 bayt veya 16 baytlık öğe vektörleri. Her öğenin 1, 2, 4 veya 8 bayt olabileceği 8 bayt veya 16 baytlık boyutuna hizalanır.
- HFA (Homojen Kayan Nokta Toplama) – Kayan veya çift olmak üzere 2 ila 4 özdeş kayan nokta üyesine sahip bir veri türü.
- HVA (Homojen Kısa Vektör Toplama) – 2 ila 4 özdeş Kısa Vektör üyesi olan bir veri türü.
Temel gereksinimler
Windows'un ARM64 sürümü, ARMv8 veya sonraki bir mimaride her zaman çalıştırıldığını varsayalım. Hem kayan nokta hem de NEON desteğinin donanımda mevcut olduğu varsayılır.
ARMv8 belirtimi, hem AArch32 hem de AArch64 için yeni isteğe bağlı şifreleme ve CRC yardımcı opcode'larını açıklar. Bunlar için destek şu anda isteğe bağlıdır ancak önerilir. Bu işlem kodlarından yararlanmak için, uygulamalar önce varoluşları için çalışma zamanı denetimleri yapmalıdır.
Endianness
Windows'un ARM32 sürümünde olduğu gibi, ARM64'te Windows küçük endian modunda yürütülür. AArch64'te çekirdek modu desteği olmadan soniansı değiştirmek zordur, bu nedenle zorlanması daha kolaydır.
Hizalama
ARM64 üzerinde çalışan Windows, CPU donanımının yanlış hizalanmış erişimleri saydam bir şekilde işlemesini sağlar. AArch32'den yapılan bir geliştirmede, bu destek artık tüm tamsayı erişimleri (çok sözcüklü erişimler dahil) ve kayan nokta erişimleri için de çalışır.
Ancak, kazınmamış (cihaz) belleğe erişimler yine de her zaman hizalanmalıdır. Kod, kazınmamış bellekten yanlış hizalanmış verileri okuyabiliyor veya yazabiliyorsa, tüm erişimleri hizaladığından emin olmalıdır.
Yerel ayarlar için varsayılan düzen hizalaması:
Bayt cinsinden boyut | Bayt cinsinden hizalama |
---|---|
1 | Kategori 1 |
2 | 2 |
3, 4 | 4 |
> 4 | 8 |
Genel ayarlar ve statikler için varsayılan düzen hizalaması:
Bayt cinsinden boyut | Bayt cinsinden hizalama |
---|---|
1 | 1 |
2 - 7 | 4 |
8 - 63 | 8 |
>= 64 | 16 |
Tamsayı yazmaçları
AArch64 mimarisi 32 tamsayı kaydını destekler:
Kaydol | Uçuculuk | Role |
---|---|---|
x0-x8 | Uçucu | Parametre/Sonuç karalama yazmaçları |
x9-x15 | Uçucu | Karalama yazmaçları |
x16-x17 | Uçucu | Yordam içi-çağrı karalama yazmaçları |
x18 | Yok | Ayrılmış platform yazmaç: çekirdek modunda geçerli işlemci için KPCR'ye işaret eder; Kullanıcı modunda TEB'e işaret |
x19-x28 | Geçici olmayan | Karalama yazmaçları |
x29/fp | Geçici olmayan | Çerçeve işaretçisi |
x30/lr | Her ikisi | Bağlantı Kaydı: Çağıran işlevinin kendi dönüşü için bunu koruması gerekir, ancak çağıranın değeri kaybolur. |
Her yazmaca tam 64 bit değer (x0-x30 aracılığıyla) veya 32 bit değer (w0-w30 aracılığıyla) olarak erişilebilir. 32 bit işlemler, sonuçlarını 64 bit'e kadar sıfır genişletir.
Parametre yazmaçlarının kullanımıyla ilgili ayrıntılar için Parametre geçirme bölümüne bakın.
AArch32'nin aksine, program sayacı (PC) ve yığın işaretçisi (SP) dizine alınan yazmaçlar değildir. Erişimleri sınırlıdır. Ayrıca x31 yazmaç olmadığını da unutmayın. Bu kodlama özel amaçlar için kullanılır.
ÇERÇEVE işaretçisi (x29), ETW ve diğer hizmetler tarafından kullanılan hızlı yığın yürüme ile uyumluluk için gereklidir. Yığındaki önceki {x29, x30} çiftine işaret etmelidir.
Kayan nokta/SIMD yazmaçları
AArch64 mimarisi, aşağıda özetlenen 32 kayan nokta/SIMD yazmaçını da destekler:
Kaydol | Uçuculuk | Role |
---|---|---|
v0-v7 | Uçucu | Parametre/Sonuç karalama yazmaçları |
v8-v15 | Her ikisi | Düşük 64 bit Geçici Değildir. Yüksek 64 bit Geçicidir. |
v16-v31 | Uçucu | Karalama yazmaçları |
Her yazmaç tam 128 bit değer olarak erişilebilir (v0-v31 veya q0-q31 aracılığıyla). 64 bit değer olarak (d0-d31 aracılığıyla), 32 bit değer olarak (s0-s31 aracılığıyla), 16 bit değer olarak (h0-h31 aracılığıyla) veya 8 bit değer olarak (b0-b31 aracılığıyla) erişilebilir. 128 bitten küçük erişimler yalnızca tam 128 bit yazmaç alt bitlerine erişir. Aksi belirtilmedikçe kalan bitleri dokunulmadan bırakırlar. (AArch64, küçük yazmaçların büyük yazmaçların üzerine toplandığı AArch32'den farklıdır.)
Kayan nokta denetim yazmaç (FPCR) içindeki çeşitli bit alanları üzerinde belirli gereksinimlere sahiptir:
Bits | Anlamı | Uçuculuk | Role |
---|---|---|---|
26 | AHP | Geçici Olmayan | Alternatif yarı duyarlık denetimi. |
25 | DN | Geçici Olmayan | Varsayılan NaN modu denetimi. |
24 | FZ | Geçici olmayan | Sıfıra boşaltma modu denetimi. |
23-22 | RMode | Geçici olmayan | Yuvarlama modu denetimi. |
15,12-8 | IDE/IXE/vb. | Geçici Olmayan | Özel durum yakalama etkinleştirme bitleri, her zaman 0 olmalıdır. |
Sistem kayıtları
AArch32 gibi, AArch64 belirtimi de sistem tarafından denetlenen üç "iş parçacığı kimliği" yazmaç sağlar:
Kaydol | Role |
---|---|
TPIDR_EL0 | Ayrılmış. |
TPIDRRO_EL0 | Geçerli işlemcinin CPU numarasını içerir. |
TPIDR_EL1 | Geçerli işlemci için KPCR yapısını gösterir. |
Kayan nokta özel durumları
AArch64 sistemlerinde IEEE kayan nokta özel durumları için destek isteğe bağlıdır. Donanım kayan nokta özel durumları olan işlemci varyantları için, Windows çekirdeği özel durumları sessizce yakalar ve bunları FPCR yazmaçta örtük olarak devre dışı bırakır. Bu yakalama, işlemci varyantları arasında normalleştirilmiş davranış sağlar. Aksi takdirde, özel durum desteği olmayan bir platformda geliştirilen kod, destek içeren bir platformda çalıştırılırken kendisini beklenmeyen özel durumlarla karşılaşabilir.
Parametre geçirme
Variadic olmayan işlevler için, Windows ABI parametre geçirme için ARM tarafından belirtilen kuralları izler. Bu kurallar doğrudan AArch64 Mimarisi için Yordam Çağrısı Standardı'ndan alıntılanır:
Aşama A – Başlatma
Bu aşama, bağımsız değişkenlerin işlenmesi başlamadan önce tam olarak bir kez yapılır.
Sonraki Genel Amaçlı Kayıt Numarası (NGRN) sıfır olarak ayarlanır.
Sonraki SIMD ve Kayan Nokta Kayıt Numarası (NSRN) sıfır olarak ayarlanır.
Sonraki yığılmış bağımsız değişken adresi (NSAA), geçerli yığın işaretçisi değerine (SP) ayarlanır.
Aşama B – Bağımsız değişkenlerin ön doldurması ve uzantısı
Listedeki her bağımsız değişken için aşağıdaki listeden ilk eşleşen kural uygulanır. Hiçbir kural eşleşmiyorsa bağımsız değişken değiştirilmeden kullanılır.
Bağımsız değişken türü, hem çağıran hem de çağıran tarafından statik olarak belirlenemeyen bir Bileşik Tür ise, bağımsız değişken belleğe kopyalanır ve bağımsız değişken kopyanın işaretçisiyle değiştirilir. (C/C++ dilinde bu tür türler yoktur, ancak bunlar başka dillerde veya dil uzantılarında bulunur).
Bağımsız değişken türü bir HFA veya HVA ise, bağımsız değişken değiştirilmeden kullanılır.
Bağımsız değişken türü 16 bayttan büyük bir Bileşik Türse, bağımsız değişken çağıran tarafından ayrılan belleğe kopyalanır ve bağımsız değişken kopyanın işaretçisiyle değiştirilir.
Bağımsız değişken türü Bileşik Tür ise, bağımsız değişkenin boyutu 8 bayt'ın en yakın katına yuvarlanmış olur.
Aşama C – Bağımsız değişkenlerin yazmaçlara ve yığına atanma
Listedeki her bağımsız değişken için, bağımsız değişken ayrılana kadar aşağıdaki kurallar sırayla uygulanır. Bir bağımsız değişken bir yazmaca atandığında, yazmaçtaki kullanılmayan bitlerin belirtilmemiş değeri olur. Bir bağımsız değişken bir yığın yuvasına atanmışsa, kullanılmayan doldurma baytlarının belirtilmemiş değeri vardır.
Bağımsız değişken Yarım, Tek, Çift veya Dört Duyarlıklı Kayan Nokta veya Kısa Vektör Türü ise ve NSRN 8'den küçükse, bağımsız değişken v[NSRN] yazmacının en az önemli bitlerine ayrılır. NSRN bir artırılır. Bağımsız değişken şimdi ayrılmıştır.
Bağımsız değişken bir HFA veya HVA ise ve yeterli ayrılmamış SIMD ve Kayan nokta yazmaçları varsa (NSRN + 8 ≤ üye sayısı), bağımsız değişken HFA veya HVA'nın her üyesi için bir tane olmak üzere SIMD ve Kayan Nokta Yazmaçlarına ayrılır. NSRN, kullanılan yazmaç sayısına göre artırılır. Bağımsız değişken şimdi ayrılmıştır.
Bağımsız değişken bir HFA veya HVA ise, NSRN 8 olarak ayarlanır ve bağımsız değişkenin boyutu 8 bayt'ın en yakın katına yuvarlanir.
Bağımsız değişken bir HFA, bir HVA, Dört duyarlıklı Kayan nokta veya Kısa Vektör Türü ise, NSAA 8'in büyük veya bağımsız değişkenin türünün Doğal Hizalamasına yuvarlanmış olur.
Bağımsız değişken Yarım veya Tek Duyarlıklı Kayan Nokta türüyse, bağımsız değişkenin boyutu 8 bayt olarak ayarlanır. Bunun etkisi, bağımsız değişkenin 64 bit yazmaçların en az önemli bitlerine ve kalan bitlerin belirtilmeyen değerlerle doldurulmuş olması gibidir.
Bağımsız değişken HFA, HVA, Yarım, Tek, Çift veya Dört duyarlıklı Kayan Nokta veya Kısa Vektör Türü ise, bağımsız değişken ayarlanan NSAA'daki belleğe kopyalanır. NSAA, bağımsız değişkenin boyutuna göre artırılır. Bağımsız değişken şimdi ayrılmıştır.
Bağımsız değişken bir İntegral veya İşaretçi Türü ise, bağımsız değişkenin boyutu 8 bayttan küçük veya buna eşitse ve NGRN 8'den küçükse, bağımsız değişken x[NGRN] içindeki en az önemli bitlere kopyalanır. NGRN bir artırılır. Bağımsız değişken şimdi ayrılmıştır.
Bağımsız değişkenin hizalaması 16 ise, NGRN bir sonraki çift sayıya yuvarlanırsa.
Bağımsız değişken tam sayı türündeyse, bağımsız değişkenin boyutu 16'ya eşittir ve NGRN 7'den küçükse, bağımsız değişken x[NGRN] ve x[NGRN+1] olarak kopyalanır. x[NGRN] bağımsız değişkenin bellek gösteriminin küçük adreslenmiş çift sözcüğünü içermelidir. NGRN iki artırılır. Bağımsız değişken şimdi ayrılmıştır.
Bağımsız değişken bir Bileşik Tür ise ve bağımsız değişkenin çift sözcüklerinin boyutu 8 eksi NGRN'den fazla değilse, bağımsız değişken x[NGRN] tarihinden başlayarak ardışık genel amaçlı yazmaçlara kopyalanır. Bağımsız değişken, bellekten ardışık yazmaçları yükleyen uygun bir LDR yönergeleri dizisiyle çift sözcükle hizalanmış bir adresten yazmaçlara yüklenmiş gibi geçirilir. Yazmaçların kullanılmayan bölümlerinin içeriği bu standart tarafından belirtilmez. NGRN, kullanılan yazmaç sayısına göre artırılır. Bağımsız değişken şimdi ayrılmıştır.
NGRN 8 olarak ayarlanır.
NSAA, bağımsız değişkenin türünün 8'in üzerine veya Doğal Hizalama'ya yuvarlanmış.
Bağımsız değişken bileşik bir türse, bağımsız değişken ayarlanan NSAA'daki belleğe kopyalanır. NSAA, bağımsız değişkenin boyutuna göre artırılır. Bağımsız değişken şimdi ayrılmıştır.
Bağımsız değişkenin boyutu 8 bayttan küçükse, bağımsız değişkenin boyutu 8 bayt olarak ayarlanır. Bunun etkisi, bağımsız değişkenin 64 bitlik bir kaydın en az önemli bitlerine kopyalandığı ve kalan bitlerin belirtilmeyen değerlerle doldurulduğudur.
Bağımsız değişken, ayarlanan NSAA'daki belleğe kopyalanır. NSAA, bağımsız değişkenin boyutuna göre artırılır. Bağımsız değişken şimdi ayrılmıştır.
Ek: Variadic işlevleri
Değişken sayıda bağımsız değişken kullanan işlevler aşağıdaki gibi yukarıdan farklı şekilde işlenir:
Tüm bileşikler aynı şekilde işlenir; HTA'lara veya HVA'lara özel işlem yapılmaz.
SIMD ve Kayan Nokta Yazmaçları kullanılmaz.
Etkili bir şekilde, yığının ilk 64 baytının x0-x7'ye yüklendiği ve kalan tüm yığın bağımsız değişkenlerinin normal şekilde yerleştirildiği sanal bir yığına bağımsız değişkenleri ayırmak için aşağıdaki C.12–C.15 kurallarıyla aynıdır.
Dönüş değerleri
İntegral değerler x0 cinsinden döndürülür.
Kayan nokta değerleri uygun şekilde s0, d0 veya v0 cinsinden döndürülür.
Aşağıdakilerin tümü ayrı tutulsa bir tür HFA veya HVA olarak kabul edilir:
- Boş değil.
- Önemsiz olmayan varsayılan veya kopya oluşturucuları, yıkıcıları veya atama işleçleri yoktur,
- Tüm üyeleri aynı HFA veya HVA türüne sahiptir ya da diğer üyelerin HFA veya HVA türleriyle eşleşen float, double veya neon türleridir.
Dört veya daha az öğe içeren HVA değerleri s0-s3, d0-d3 veya v0-v3'te uygun şekilde döndürülür.
Değer tarafından döndürülen türler, belirli özelliklere sahip olup olmadıklarına ve işlevin statik olmayan bir üye işlev olup olmadığına bağlı olarak farklı şekilde işlenir. Bu özelliklerin tümüne sahip türler,
- C++14 standart tanımına göre toplanır, yani kullanıcı tarafından sağlanan oluşturucular, özel veya korumalı statik olmayan veri üyeleri, temel sınıflar ve sanal işlevler yoktur ve
- önemsiz bir kopya atama işlecine sahipler ve
- Önemsiz bir yok edicileri var.
ve üye olmayan işlevler veya statik üye işlevleri tarafından döndürülür, aşağıdaki dönüş stilini kullanın:
- Dört veya daha az öğe içeren HTA'lar olan türler s0-s3, d0-d3 veya v0-v3'te uygun şekilde döndürülür.
- 8 bayttan küçük veya buna eşit türler x0 cinsinden döndürülür.
- x0 ve x1'de 16 bayttan küçük veya buna eşit türler döndürülür ve x0 alt sıra 8 bayt içerir.
- Diğer toplama türleri için çağıran, sonucu tutmak için yeterli boyutta ve hizalamada bir bellek bloğu ayıracaktır. Bellek bloğunun adresi, x8'deki işleve ek bir bağımsız değişken olarak geçirilir. Çağıran, alt işlemin yürütülmesi sırasında herhangi bir noktada sonuç bellek bloğunu değiştirebilir. Çağrılan, x8'de depolanan değeri korumak için gerekli değildir.
Diğer tüm türler şu kuralı kullanır:
- Arayanın, sonucu tutmak için yeterli boyutta ve hizalamada bir bellek bloğu ayırması gerekir. Bellek bloğunun adresi, x0'da işleve ek bir bağımsız değişken olarak geçirilir veya x0'da $this geçirilirse x1. Çağıran, alt işlemin yürütülmesi sırasında herhangi bir noktada sonuç bellek bloğunu değiştirebilir. Çağıran, x0'da bellek bloğunun adresini döndürür.
Yığın
ARM tarafından ortaya konan ABI'nin ardından yığın her zaman 16 bayt hizalanmış olarak kalmalıdır. AArch64, SP 16 bayt hizalanmadığı ve SP göreli yük veya deposu yapıldığında yığın hizalama hataları oluşturan bir donanım özelliği içerir. Windows, bu özellik her zaman etkin olarak çalışır.
4k veya daha fazla yığın ayıran işlevler, son sayfadan önceki her sayfaya sırayla dokunulmasını sağlamalıdır. Bu eylem, Windows'un yığını genişletmek için kullandığı koruma sayfalarını hiçbir kodun "atlamamasını" sağlar. Dokunma işlemi genellikle yardımcı tarafından yapılır ve toplam yığın ayırmayı __chkstk
x15'te 16'ya bölen özel bir çağrı kuralı vardır.
Kırmızı bölge
Geçerli yığın işaretçisinin hemen altındaki 16 baytlık alan analiz ve dinamik düzeltme eki uygulama senaryoları tarafından kullanılmak üzere ayrılmıştır. Bu alan, [sp, #-16] konumunda iki yazmacı depolayan ve bunları rastgele amaçlarla geçici olarak kullanan dikkatle oluşturulan kodun eklenmesine izin verir. Windows çekirdeği, hem kullanıcı hem de çekirdek modunda bir özel durum veya kesme yapılırsa bu 16 bayt'ın üzerine yazılmadığını garanti eder.
Çekirdek yığını
Windows'ta varsayılan çekirdek modu yığını altı sayfadır (24k). Çekirdek modunda büyük yığın arabellekleri olan işlevlere daha fazla dikkat edin. Küçük bir boşlukla birlikte kötü zamanlanmış bir kesme gelebilir ve bir yığın panik hata denetimi oluşturabilir.
Yığınla yürüme
Windows içindeki kod, hızlı yığın yürümeyi etkinleştirmek için çerçeve işaretçileri etkin (/Oy-) ile derlenmiş. Genellikle, x29 (fp) zincirdeki bir sonraki bağlantıya işaret eder; bu bir {fp, lr} çiftidir ve işaretçiyi yığındaki önceki çerçeveye ve dönüş adresine gösterir. Üçüncü taraf kodunun, gelişmiş profil oluşturma ve izleme için çerçeve işaretçilerini etkinleştirmesi de teşvik edilir.
Özel durum geri alma
Özel durum işleme sırasında geri sarmalama, geri alma kodlarının kullanılmasıyla yardımcı olabilir. Geri sarma kodları, yürütülebilir dosyanın .xdata bölümünde depolanan bir bayt dizisidir. Bir işlevin prologunun etkilerini çağıranın yığın çerçevesine yedekleme hazırlığında geri alınabilecek şekilde, prolog ve epilogun çalışmasını soyut bir şekilde açıklar. Geri sarma kodları hakkında daha fazla bilgi için bkz . ARM64 özel durum işleme.
ARM EABI ayrıca, geri alma kodlarını kullanan bir özel durum geri alma modeli belirtir. Ancak, sunulan belirtim Windows'ta geri sarma için yetersizdir ve bilgisayarın bir işlev prologue veya epilogunun ortasında olduğu durumları işlemesi gerekir.
Dinamik olarak oluşturulan kod, oluşturulan kodun özel durum işlemeye katılabilmesi için ve ilişkili işlevler aracılığıyla RtlAddFunctionTable
dinamik işlev tablolarıyla açıklanmalıdır.
Döngü sayacı
Tüm ARMv8 CPU'lar, Windows'un kullanıcı modu dahil olmak üzere herhangi bir özel durum düzeyinde okunabilir olarak yapılandırılan 64 bitlik bir kayıt olan bir döngü sayacı kaydını desteklemek için gereklidir. Özel PMCCNTR_EL0 yazmacı aracılığıyla, derleme kodunda MSR opcode veya _ReadStatusReg
C/C++ kodundaki iç kod kullanılarak erişilebilir.
Buradaki döngü sayacı gerçek bir döngü sayacıdır, duvar saati değildir. Sayım sıklığı işlemci sıklığına göre değişir. Döngü sayacının sıklığını bilmeniz gerektiğini düşünüyorsanız, döngü sayacını kullanmamalısınız. Bunun yerine, kullanmanız QueryPerformanceCounter
gereken duvar saati saatini ölçmek istiyorsunuz.
Ayrıca bkz.
Genel Visual C++ ARM Geçiş Sorunları
ARM64 özel durum işleme