Sdílet prostřednictvím


Přehled konvencí ARM64EC ABI

ARM64EC je binární rozhraní aplikace (ABI), které umožňuje binárním souborům ARM64 spouštět nativně a interoperativně s kódem x64. Konkrétně ARM64EC ABI se řídí softwarovými konvencemi x64, včetně konvence volání, použití zásobníku a zarovnání dat, což ARM64EC a x64 kód interoperabilní. Operační systém emuluje část binárního souboru x64. (ES v ARM64EC je zkratka pro emulaci kompatibilní.)

Další informace o konvencích ABI pro platformu x64 a ARM64 najdete v tématu Přehled konvencí X64 ABI a přehledu konvencí ARM64 ABI.

ARM64EC nevyřeší rozdíly v modelu paměti mezi architekturami založenými na platformě x64 a ARM. Další informace najdete v tématu Běžné problémy s migrací ARM v jazyce Visual C++.

Definice

  • ARM64 – Stream kódu pro procesy ARM64, které obsahují tradiční kód ARM64.
  • ARM64EC – datový proud kódu, který využívá podmnožinu registru ARM64, která poskytuje interoperabilitu s kódem x64.

Mapování registru

Procesy x64 můžou obsahovat vlákna, na kterých běží ARM64EC kód. Proto je vždy možné načíst kontext registru x64, ARM64EC používá podmnožinu registrů jader ARM64, které mapují 1:1 na emulované registry x64. Důležité je, že ARM64EC nikdy nepoužívá registry mimo tuto podmnožinu, s výjimkou čtení adresy TEB (Thread Environment Block) z x18.

Nativní procesy ARM64 by se neměly při rekompilování některých nebo mnoha funkcí rekompilovat jako ARM64EC. Aby se zachoval výkon, ABI se řídí těmito principy:

  • Podmnožina ARM64EC registru zahrnuje všechny registry, které jsou součástí konvence volání funkce ARM64.

  • Konvence volání ARM64EC se přímo mapuje na konvenci volání ARM64.

Speciální pomocné rutiny, jako je __chkstk_arm64ec použití vlastních konvencí volání a registrů Tyto registry jsou také zahrnuty v ARM64EC podmnožině registrů.

Mapování registru pro celočíselné registry

registrace ARM64EC Registrace x64 ARM64EC konvence volání Konvence volání ARM64 x64 – konvence volání
x0 rcx volatile volatile volatile
x1 rdx volatile volatile volatile
x2 r8 volatile volatile volatile
x3 r9 volatile volatile volatile
x4 r10 volatile volatile volatile
x5 r11 volatile volatile volatile
x6 mm1 (nízkých 64 bitů registru x87 R1 ) volatile volatile volatile
x7 mm2 (nízkých 64 bitů registru x87 R2 ) volatile volatile volatile
x8 rax volatile volatile volatile
x9 mm3 (nízkých 64 bitů registru x87 R3 ) volatile volatile volatile
x10 mm4 (nízkých 64 bitů registru x87 R4 ) volatile volatile volatile
x11 mm5 (nízkých 64 bitů registru x87 R5 ) volatile volatile volatile
x12 mm6 (nízkých 64 bitů registru x87 R6 ) volatile volatile volatile
x13 zamítnutý volatile
x14 N/A zamítnutý volatile
x15 mm7 (nízkých 64 bitů registru x87 R7 ) volatile volatile volatile
x16 Vysoká 16 bitů každého z registrů x87 R0-R3 volatile(xip0) volatile(xip0) volatile
x17 Vysoká 16 bitů každého z registrů x87 R4-R7 volatile(xip1) volatile(xip1) volatile
x18 GS.base fixed(TEB) fixed(TEB) fixed(TEB)
x19 r12 nestálé nestálé nestálé
x20 r13 nestálé nestálé nestálé
x21 r14 nestálé nestálé nestálé
x22 r15 nestálé nestálé nestálé
x23 zamítnutý nestálé
x24 N/A zamítnutý nestálé
x25 rsi nestálé nestálé nestálé
x26 rdi nestálé nestálé nestálé
x27 rbx nestálé nestálé nestálé
x28 zamítnutý zamítnutý
fp rbp nestálé nestálé nestálé
lr mm0 (nízkých 64 bitů registru x87 R0 ) Oba Oba Oba
sp rsp nestálé nestálé nestálé
pc rip ukazatel instrukce ukazatel instrukce ukazatel instrukce
PSTATEpodmnožina: NZSS/C//V/1, 2 RFLAGS podmnožina: SF/ZF/CF/OF/TF volatile volatile volatile
RFLAGS podmnožina: PF/AF N/A volatile
RFLAGS podmnožina: DF N/A nestálé

1 Vyhněte se přímému čtení, zápisu nebo výpočtu mapování mezi PSTATE a RFLAGS. Tyto bity se můžou v budoucnu používat a můžou se změnit.

2 Příznak pro přenos ARM64EC C je inverzní příznak k přenosu CF x64 pro operace odčítání. Neexistuje žádná zvláštní manipulace, protože příznak je nestálý a proto je při přechodu mezi funkcemi (ARM64EC a x64) odpadlý.

Registrace mapování vektorových registrů

registrace ARM64EC Registrace x64 ARM64EC konvence volání Konvence volání ARM64 x64 – konvence volání
v0-v5 xmm0-xmm5 volatile volatile volatile
v6-v7 xmm6-xmm7 volatile volatile nestálé
v8-v15 xmm8-xmm15 volatile 1 volatile 1 nestálé
v16-v31 xmm16-xmm31 zamítnutý volatile nepovolené (emulátor x64 nepodporuje AVX-512)
FPCR 2 MXCSR[15:6] nestálé nestálé nestálé
FPSR 2 MXCSR[5:0] volatile volatile volatile

1 Tyto registry ARM64 jsou speciální v tom, že nižší 64 bity jsou nestálé, ale horní 64 bity jsou nestálé. Z pohledu volajícího x64 jsou efektivně nestálé, protože volaný by volaný vyhazoval data.

2 Vyhněte se přímému čtení, psaní nebo výpočtu mapování FPCR a FPSR. Tyto bity se můžou v budoucnu používat a můžou se změnit.

Balení struktur

ARM64EC se řídí stejnými pravidly balení struktur, která se používají pro x64 k zajištění interoperability mezi ARM64EC kódem a kódem x64. Další informace a příklady balení struktur x64 naleznete v tématu Přehled konvencí X64 ABI.

Pomocné rutiny ABI emulace

ARM64EC kódu a thunks používají pomocné rutiny emulace k přechodu mezi funkcemi x64 a ARM64EC.

Následující tabulka popisuje každou speciální rutinu ABI a registru používá ABI. Rutiny neupravují uvedené zachované registry ve sloupci ABI. O nezaregistrovaných registrech by se neměly provádět žádné předpoklady. Na disku mají rutinní ukazatele ABI hodnotu null. Při načítání zavaděč aktualizuje ukazatele tak, aby ukazovaly na rutiny emulátoru x64.

Název Popis ABI
__os_arm64x_dispatch_call_no_redirect Volal by exit thunk pro volání cíle x64 (funkce x64 nebo x64 fast-forward sekvence). Rutina odešle ARM64EC návratovou adresu (v LR registru) následovanou adresou instrukce, která uspěje blr x16 pokyn, který vyvolá emulátor x64. Potom spustí instrukce.blr x16 návratová hodnota v x8 (rax)
__os_arm64x_dispatch_ret Zavolá se vstupním záznamem, který se vrátí do volajícího x64. Zobrazí návratovou adresu x64 ze zásobníku a vyvolá emulátor x64, aby na ni přeskočil.
__os_arm64x_check_call Volal by ARM64EC kód s ukazatelem na konec thunk a nepřímá ARM64EC cílová adresa ke spuštění. Cíl ARM64EC se považuje za opravitelný a provádění se vždy vrátí volajícímu se stejnými daty, se kterými byl volán, nebo s upravenými daty. Argumenty:
x9: Cílová adresa
x10: Adresa výstupního thunku
x11: Adresa posloupnosti rychlého předávání

Ven:
x9: Pokud byla cílová funkce objížděna, obsahuje adresu rychlého předávání.
x10: Adresa výstupního thunku
x11: Pokud byla funkce objížděna, obsahuje adresu výstupního záznamu. Jinak cílová adresa přeskočí na

Zachované rejstříky: x0-x8, x15 ().chkstk a q0-q7
__os_arm64x_check_icall Volal by ARM64EC kód s ukazatelem na konec thunk pro zpracování skoku na cílovou adresu, která je x64 nebo ARM64EC. Pokud je cíl x64 a kód x64 nebyl opraven, rutina nastaví registr cílových adres. Odkazuje na ARM64EC verzi funkce, pokud existuje. V opačném případě nastaví registr tak, aby ukazoval na výstupní blok, který přejde na cíl x64. Pak se vrátí do volajícího ARM64EC kódu, který pak přeskočí na adresu v registru. Tato rutina je neoptimalizovatelní verze __os_arm64x_check_call, kde cílová adresa není v době kompilace známá.

Používá se na místě volání nepřímého volání.
Argumenty:
x9: Cílová adresa
x10: Adresa výstupního thunku
x11: Adresa posloupnosti rychlého předávání

Ven:
x9: Pokud byla cílová funkce objížděna, obsahuje adresu rychlého předávání.
x10: Adresa výstupního thunku
x11: Pokud byla funkce objížděna, obsahuje adresu výstupního záznamu. Jinak cílová adresa přeskočí na

Zachované rejstříky: x0-x8, x15 (chkstk) a q0-q7
__os_arm64x_check_icall_cfg Stejné jako __os_arm64x_check_icall ale také kontroluje, že zadaná adresa je platným cílem nepřímého volání grafu toku řízení. Argumenty:
x10: Adresa výstupního útržku
x11: Adresa cílové funkce

Ven:
x9: Pokud je cíl x64, adresa funkce. Jinak není definováno
x10: Adresa výstupního útržku
x11: Pokud je cíl x64, obsahuje adresu výstupního záznamu. V opačném případě adresa funkce

Zachované rejstříky: x0-x8, x15 (chkstk) a q0-q7
__os_arm64x_get_x64_information Získá požadovanou část živého kontextu registru x64. _Function_class_(ARM64X_GET_X64_INFORMATION) NTSTATUS LdrpGetX64Information(_In_ ULONG Type, _Out_ PVOID Output, _In_ PVOID ExtraInfo)
__os_arm64x_set_x64_information Nastaví požadovanou část živého kontextu registru x64. _Function_class_(ARM64X_SET_X64_INFORMATION) NTSTATUS LdrpSetX64Information(_In_ ULONG Type,_In_ PVOID Input, _In_ PVOID ExtraInfo)
__os_arm64x_x64_jump Používá se v úpravce bez podpisu a dalších útržcích, které přímo přesměrují (jmp) volání jiné funkce, která může mít libovolný podpis, odloží potenciální použití správného převodu na skutečný cíl. Argumenty:
x9: cíl přejít na

Všechny registry parametrů se zachovají (přeposílané)

Thunks

Thunks jsou mechanismy nízké úrovně pro podporu ARM64EC a funkcí x64, které navzájem volají. Existují dva typy: vstupní bloky pro zadávání ARM64EC funkcí a ukončení thunků pro volání funkcí x64.

Záznam thunk a vnitřní vstupní thunks: x64 to ARM64EC volání funkce

Pro podporu volajících x64, když je funkce C/C++ zkompilována jako ARM64EC, vygeneruje sada nástrojů jeden záznam skládající se z ARM64EC strojového kódu. Vnitřní objekty mají vlastní záznam. Všechny ostatní funkce sdílejí záznamový blok se všemi funkcemi, které mají odpovídající konvenci volání, parametry a návratový typ. Obsah thunk závisí na konvenci volání funkce C/C++.

Kromě zpracování parametrů a návratové adresy přemostí thunk rozdíly v nestálosti mezi ARM64EC a vektorovými registry x64 způsobenými mapováním ARM64EC vektorového registru:

registrace ARM64EC Registrace x64 ARM64EC konvence volání Konvence volání ARM64 x64 – konvence volání
v6-v15 xmm6-xmm15 volatile, ale uložen/obnoven v záznamu thunk (x64 to ARM64EC) volatile or partially volatile upper 64 bits nestálé

Záznam thunk provede následující akce:

Číslo parametru Využití zásobníku
0-4 Ukládá ARM64EC v6 a v7 do domovského prostoru přiděleného volajícím.

Vzhledem k tomu, že volaný je ARM64EC, který nemá představu o domovském prostoru, uložené hodnoty nejsou zahlcené.

Přidělí dalších 128 bajtů v zásobníku a uloží ARM64EC v8 prostřednictvím v15.
5-8 x4 = 5. parametr ze zásobníku
x5 = 6. parametr ze zásobníku
x6 = 7. parametr ze zásobníku
x7 = 8. parametr ze zásobníku

Pokud je parametr SIMD, v4-v7 použijí se místo toho registry.
9+ AlignUp(NumParams - 8 , 2) * 8 Přidělí bajty v zásobníku. *

Zkopíruje 9. a zbývající parametry do této oblasti.

* Zarovnání hodnoty na sudé číslo zaručuje, že zásobník zůstane zarovnaný na 16 bajtů.

Pokud funkce přijímá 32bitový celočíselnou parametr, je tento blok povolený pouze nasdílení 32 bitů namísto plných 64 bitů nadřazeného registru.

V dalším kroku použije thunk instrukce ARM64 bl k volání ARM64EC funkce. Po návratu funkce se zobrazí thunk:

  1. Vrátí zpět všechna přidělení zásobníku.
  2. Zavolá pomocnou rutinu emulátoru __os_arm64x_dispatch_ret , aby se vysuhla návratová adresa x64 a obnovila emulaci x64.

Konec thunk: ARM64EC volání funkce x64

Pro každé volání, které ARM64EC funkce C/C++ provádí pro potenciální kód x64, vygeneruje sada nástrojů MSVC ukončovací blok. Obsah thunk závisí na parametrech volaného x64 a na tom, zda volaný používá standardní konvenci volání nebo __vectorcall. Kompilátor získá tyto informace z deklarace funkce pro volaný.

Za prvé, thunk nasdílí zpáteční adresu, která je v ARM64EC lr registru a fiktivní 8 bajtová hodnota, aby se zajistilo, že zásobník je zarovnaný na 16 bajtů. Za druhé, thunk zpracovává parametry:

Číslo parametru Využití zásobníku
0-4 Přidělí 32 bajtů domovského prostoru v zásobníku.
5-8 Přiděluje AlignUp(NumParams - 4, 2) * 8 více bajtů vyšších v zásobníku. *

Zkopíruje 5. a všechny další parametry z ARM64EC x4-x7 do tohoto nadbytečného prostoru.
9+ Zkopíruje 9. a zbývající parametry do nadbytečného prostoru.

* Zarovnání hodnoty na sudé číslo zaručuje, že zásobník zůstane zarovnaný na 16 bajtů.

Za třetí, thunk volá pomocník emulátoru __os_arm64x_dispatch_call_no_redirect vyvolá emulátor emulátoru x64 ke spuštění funkce x64. Hovor musí být blr x16 instrukce (pohodlně, x16 je nestálý registr). Vyžaduje blr x16 se instrukce, protože emulátor x64 analyzuje tuto instrukci jako nápovědu.

Funkce x64 se obvykle pokouší vrátit do pomocné rutiny emulátoru pomocí instrukce x64 ret . V tomto okamžiku emulátor x64 zjistí, že je v ARM64EC kódu. Pak přečte předchozí 4bajtů nápovědu, která se stane instrukce ARM64 blr x16 . Vzhledem k tomu, že tato nápověda indikuje, že návratová adresa je v této pomocné rutině, emulátor přeskočí přímo na tuto adresu.

Funkce x64 se může vrátit do pomocné rutiny emulátoru pomocí jakékoli instrukce větve, včetně x64 jmp a call. Emulátor také zpracovává tyto scénáře.

Když se pomocná rutina vrátí k útržku, je to:

  1. Vrácení všech přidělení zásobníku zpět
  2. Zobrazí ARM64EC lr registraci.
  3. Spustí instrukce ARM64 ret lr .

dekorace názvu funkce ARM64EC

Název ARM64EC funkce má sekundární dekoraci použitou po jakékoli dekoraci specifické pro jazyk. U funkcí s propojením jazyka C (ať už zkompilovaným jako C nebo pomocí extern "C") # je před názvem. Pro funkce zdobené jazykem $$h C++ se značka vloží do názvu.

foo         => #foo
?foo@@YAHXZ => ?foo@@$$hYAHXZ

__vectorcall

Sada nástrojů ARM64EC v současné době nepodporuje __vectorcall. Kompilátor vygeneruje chybu, když zjistí __vectorcall použití s ARM64EC.

Viz také

Principy ARM64EC ABI a kódu sestavení
Běžné problémy s migrací ARM v jazyce Visual C++
Zdobené názvy