Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
ARM64EC ist eine Binärschnittstelle (Application Binary Interface, ABI), mit der ARM64-Binärdateien nativ und interoperabel mit x64-Code ausgeführt werden können. Insbesondere folgt die ARM64EC ABI x64-Softwarekonventionen, einschließlich Aufrufkonventionen, Stapelnutzung und Datenausrichtung, wodurch ARM64EC- und x64-Code interoperabel werden. Das Betriebssystem emuliert den x64-Teil der Binärdatei. (Die EC in ARM64EC steht für emulationskompatibel.)
Weitere Informationen zu den X64- und ARM64-ABIs finden Sie unter Übersicht über x64 ABI-Konventionen und Übersicht über ARM64 ABI-Konventionen.
ARM64EC löst keine Unterschiede zwischen x64- und ARM-basierten Architekturen im Speichermodell. Weitere Informationen finden Sie unter Allgemeine Probleme mit der Migration von Microsoft C++ ARM.
Definitionen
- ARM64 – Der Codestream für ARM64-Prozesse, die herkömmlichen ARM64-Code enthalten.
- ARM64EC – Der Codedatenstrom, der eine Teilmenge des ARM64-Registers verwendet, um die Interoperabilität mit x64-Code bereitzustellen.
Registerabbildung
x64-Prozesse enthalten möglicherweise Threads, die ARM64EC Code ausführen. Es ist daher immer möglich, einen x64-Registerkontext abzurufen, da ARM64EC eine Teilmenge der ARM64-Hauptregister verwendet, die 1:1 zu emulierten x64-Registern zuordnen. Wichtig ist, dass ARM64EC niemals Register außerhalb dieser Teilmenge verwendet, außer zum Lesen der TEB-Adresse (Thread Environment Block) aus x18.
Systemeigene ARM64-Prozesse sollten nicht in der Leistung zurücktreten, wenn einige oder viele Funktionen wie ARM64EC neu kompiliert werden. Um die Leistung aufrechtzuerhalten, folgt die ABI den folgenden Prinzipien:
Die ARM64EC Registeruntermenge enthält alle Register, die Teil der ARM64-Funktionsaufrufkonvention sind.
Die ARM64EC Anrufkonvention wird direkt der ARM64-Anrufkonvention zugeordnet.
Spezielle Hilfsroutinen wie __chkstk_arm64ec verwenden benutzerdefinierte Anrufkonventionen und -register. Diese Register sind auch in der ARM64EC Teilmenge der Register enthalten.
Registerzuordnung für ganzzahlige Register
| ARM64EC Registrier | x64-Register | ARM64EC Anrufkonvention | Aufrufkonvention bei ARM64-Systemen | Aufrufkonvention bei x64-Systemen |
|---|---|---|---|---|
x0 |
rcx |
flüchtig | flüchtig | flüchtig |
x1 |
rdx |
flüchtig | flüchtig | flüchtig |
x2 |
r8 |
flüchtig | flüchtig | flüchtig |
x3 |
r9 |
flüchtig | flüchtig | flüchtig |
x4 |
r10 |
flüchtig | flüchtig | flüchtig |
x5 |
r11 |
flüchtig | flüchtig | flüchtig |
x6 |
mm1 (niedrigere 64 Bits des x87-Registers R1) |
flüchtig | flüchtig | flüchtig |
x7 |
mm2 (untere 64 Bit des x87-Registers R2) |
flüchtig | flüchtig | flüchtig |
x8 |
rax |
flüchtig | flüchtig | flüchtig |
x9 |
mm3 (niedrige 64 Bits des x87-Registers R3) |
flüchtig | flüchtig | flüchtig |
x10 |
mm4 (niedrige 64-Bit-Anteil des x87-Registers R4) |
flüchtig | flüchtig | flüchtig |
x11 |
mm5 (niedrige 64 Bit des x87-Registers R5) |
flüchtig | flüchtig | flüchtig |
x12 |
mm6 (niedrige 64 Bits des x87-Registers R6) |
flüchtig | flüchtig | flüchtig |
x13 |
Nicht zutreffend | Nicht zulässig | flüchtig | Nicht zutreffend |
x14 |
Nicht zutreffend | Nicht zulässig | flüchtig | Nicht zutreffend |
x15 |
mm7 (untere 64 Bits des x87-Registers R7) |
flüchtig | flüchtig | flüchtig |
x16 |
Hohe 16 Bits jeder der x87 R0-R3-Register |
volatil (xip0) |
volatile (xip0) |
flüchtig |
x17 |
Hohe 16 Bits jeder der x87 R4-R7-Register |
volatile (xip1) |
volatil (xip1) |
flüchtig |
x18 |
GS.base | fixed(TEB) | fixed(TEB) | fixed(TEB) |
x19 |
r12 |
Nicht flüchtig | Nicht flüchtig | Nicht flüchtig |
x20 |
r13 |
Nicht flüchtig | Nicht flüchtig | Nicht flüchtig |
x21 |
r14 |
Nicht flüchtig | Nicht flüchtig | Nicht flüchtig |
x22 |
r15 |
Nicht flüchtig | Nicht flüchtig | Nicht flüchtig |
x23 |
Nicht verfügbar | Nicht zulässig | Nicht flüchtig | Nicht verfügbar |
x24 |
Nicht verfügbar | Nicht zulässig | Nicht flüchtig | Nicht verfügbar |
x25 |
rsi |
Nicht flüchtig | Nicht flüchtig | Nicht flüchtig |
x26 |
rdi |
Nicht flüchtig | Nicht flüchtig | Nicht flüchtig |
x27 |
rbx |
Nicht flüchtig | Nicht flüchtig | Nicht flüchtig |
x28 |
Nicht verfügbar | Nicht zulässig | Nicht zulässig | Nicht verfügbar |
fp |
rbp |
Nicht flüchtig | Nicht flüchtig | Nicht flüchtig |
lr |
mm0 (untere 64 Bits des x87-Registers R0) |
beide | beide | beide |
sp |
rsp |
Nicht flüchtig | Nicht flüchtig | Nicht flüchtig |
pc |
rip |
Anweisungszeiger | Instruktionszeiger | Anweisungszeiger |
PSTATETeilmenge: N/Z/C/V/SS1, 2 |
RFLAGSTeilmenge: SF/ZF/CF/OF/TF |
flüchtig | flüchtig | flüchtig |
| Nicht verfügbar |
RFLAGSTeilmenge: PF/AF |
Nicht verfügbar | Nicht verfügbar | flüchtig |
| Nicht verfügbar |
RFLAGSTeilmenge: DF |
Nicht zutreffend | Nicht zutreffend | Nicht flüchtig |
1 Vermeiden Sie direktes Lesen, Schreiben oder Berechnen von Zuordnungen zwischen PSTATE und RFLAGS. Diese Bits können in Zukunft verwendet werden und können sich ändern.
2 Das ARM64EC-Carry-Flag C ist das Gegenteil des x64-Carry-Flags CF für Subtraktionsoperationen. Es gibt keine spezielle Behandlung, da das Flag volatil ist und daher beim Übergang zwischen Funktionen (ARM64EC und x64) gelöscht wird.
Abbildungszuordnung für Vektorregister
| ARM64EC Registrier | x64-Register | ARM64EC Anrufkonvention | Aufrufkonvention bei ARM64-Systemen | Aufrufkonvention bei x64-Systemen |
|---|---|---|---|---|
v0-v5 |
xmm0-xmm5 |
flüchtig | flüchtig | flüchtig |
v6-v7 |
xmm6-xmm7 |
flüchtig | flüchtig | Nicht flüchtig |
v8-v15 |
xmm8-xmm15 |
volatil 1 | volatil 1 | Nicht flüchtig |
v16-v31 |
xmm16-xmm31 |
Nicht zulässig | flüchtig | nicht zulässig (der x64-Emulator unterstützt AVX-512 nicht) |
FPCR
2 |
MXCSR[15:6] |
Nicht flüchtig | Nicht flüchtig | Nicht flüchtig |
FPSR
2 |
MXCSR[5:0] |
flüchtig | flüchtig | flüchtig |
1 Diese ARM64-Register sind speziell dafür, dass die unteren 64 Bits nicht veränderlich sind, aber die oberen 64 Bits veränderlich sind. Aus der Sicht eines x64-Anrufers sind sie praktisch volatil, da der Angerufene Daten zerstören würde.
2 Vermeiden Sie direktes Lesen, Schreiben oder Berechnen von Zuordnungen von FPCR und FPSR. Diese Bits können in Zukunft verwendet werden und können sich ändern.
Strukturverpackung
ARM64EC folgt den gleichen Strukturverpackungsregeln, die für x64 verwendet werden, um die Interoperabilität zwischen ARM64EC Code und x64-Code sicherzustellen. Weitere Informationen und Beispiele für die x64-Strukturverpackung finden Sie unter Übersicht über x64 ABI-Konventionen.
Gleitkommaausnahmen
Um festzustellen, ob eine ARM-CPU Ausnahmen unterstützt, schreiben Sie einen Wert, der Ausnahmen für das FPCR-Register ermöglicht, und lesen Sie sie dann zurück. Wenn die CPU Gleitkomma-Ausnahmen unterstützt, bleiben die Bits, die unterstützten Ausnahmen entsprechen, festgelegt, während die CPU die Bits für nicht unterstützte Ausnahmen zurücksetzt.
Bei ARM64EC fängt Windows Prozessor-Gleitkomma-Ausnahmen ab und deaktiviert sie im FPCR-Register. Dadurch wird ein einheitliches Verhalten für verschiedene Prozessorvarianten sichergestellt.
Emulations-ABI-Hilfsroutinen
ARM64EC Code und Thunks verwenden Emulationshilfsroutinen für den Übergang zwischen x64 und ARM64EC Funktionen.
In der folgenden Tabelle werden die einzelnen speziellen ABI-Routinen und die ABI-Registrierungen beschrieben. Die Routinen ändern die in der Spalte ABI aufgelisteten beibehaltenen Register nicht. Es sollten keine Annahmen über nicht aufgelistete Register getroffen werden. Auf dem Datenträger sind die Zeiger der ABI-Routinen null. Zur Ladezeit aktualisiert das Ladeprogramm die Zeiger so, dass er auf die x64-Emulatorroutinen verweist.
| Name | Beschreibung | ABI |
|---|---|---|
__os_arm64x_dispatch_call_no_redirect |
Wird von einem Exit-Thunk aufgerufen, um ein x64-Ziel aufzurufen (entweder eine x64-Funktion oder eine x64-Schnellweiterleitungssequenz). Die Routine speichert die ARM64EC-Rücksprungadresse (im LR-Register), gefolgt von der Adresse der Anweisung, die einer blr x16-Anweisung folgt, welche den x64-Emulator aufruft. Anschließend wird die blr x16 Anweisung ausgeführt. |
Rückgabewert in x8 (rax) |
__os_arm64x_dispatch_ret |
Aufgerufen von einem Entry Thunk, um zum x64-Anrufer zurückzukehren. Sie entfernt die x64-Rücksprungadresse vom Stapel und ruft den x64-Emulator auf, um dorthin zu springen. | Nicht verfügbar |
__os_arm64x_check_call |
Wird von ARM64EC-Code mit einem Zeiger auf ein Exit-Thunk und die auszuführende indirekte ARM64EC-Zieladresse aufgerufen. Das ARM64EC Ziel gilt als patchbar, und die Ausführung wird immer mit denselben Daten, mit der sie aufgerufen wurde, oder mit geänderten Daten an den Aufrufer zurückgegeben | Argumente:x9: Die Zieladressex10: Die Exit-Thunk-Adressex11: Die Adresse der schnellen WeiterleitungssequenzAus: x9: Wenn die Zielfunktion umgeleitet wurde, enthält sie die Adresse der schnellen Weiterleitungssequenzx10: Die Exit-Thunk-Adressex11: Wenn die Funktion umgeleitet wurde, enthält sie die Ausgangs-Thunk-Adresse. Andernfalls springt die Zieladresse zuDie beibehaltenen Register: x0-x8, x15 (chkstk). und q0-q7 |
__os_arm64x_check_icall |
ARM64EC-Code wird mit einem Zeiger auf ein Exit-Thunk aufgerufen, um einen Sprung zu einer Zieladresse zu behandeln, die entweder x64 oder ARM64EC ist. Wenn das Ziel x64 ist und der x64-Code nicht gepatcht wurde, legt die Routine das Zieladressregister fest. Er verweist auf die ARM64EC Version der Funktion, sofern vorhanden. Andernfalls wird das Register so eingestellt, dass es auf den Ausgangs-Thunk verweist, der zum x64-Ziel wechselt. Anschließend kehrt die Funktion zum aufrufenden ARM64EC-Code zurück, der dann zur Adresse im Register springt. Diese Routine ist eine nicht optimierte Version von __os_arm64x_check_call, bei der die Zieladresse zur Kompilierungszeit nicht bekannt istWird an einem Anrufstandort eines indirekten Anrufs verwendet |
Argumente:x9: Die Zieladressex10: Die Exit-Thunk-Adressex11: Die Adresse der schnellen WeiterleitungssequenzAus: x9: Wenn die Zielfunktion umgeleitet wurde, enthält sie die Adresse der schnellen Weiterleitungssequenzx10: Die Exit-Thunk-Adressex11: Wenn die Funktion umgeleitet wurde, enthält sie die Exit-Thunk-Adresse. Andernfalls springt die Zieladresse zuBeibehaltene Register: x0-x8, x15 (chkstk) und q0-q7 |
__os_arm64x_check_icall_cfg |
Identisch mit __os_arm64x_check_icall, aber überprüft auch, dass die angegebene Adresse ein gültiges Steuerelementflussdiagramm-indirektes Anrufziel ist |
Argumente:x10: Die Adresse des Exit-Thunkx11: Die Adresse der ZielfunktionAus: x9: Wenn das Ziel x64 ist, ist dies die Adresse der Funktion. Andernfalls undefiniertx10: Die Adresse des Exit-Thunksx11: Wenn das Ziel x64 ist, enthält es die Adresse des Exit-Thunk. Andernfalls die Adresse der FunktionBeibehaltene Register: x0-x8, x15 (chkstk) und q0-q7 |
__os_arm64x_get_x64_information |
Ruft den angeforderten Teil des Live-x64-Registerkontexts ab | _Function_class_(ARM64X_GET_X64_INFORMATION) NTSTATUS LdrpGetX64Information(_In_ ULONG Type, _Out_ PVOID Output, _In_ PVOID ExtraInfo) |
__os_arm64x_set_x64_information |
Legt den angeforderten Teil des Live x64-Registrierungskontexts fest | _Function_class_(ARM64X_SET_X64_INFORMATION) NTSTATUS LdrpSetX64Information(_In_ ULONG Type,_In_ PVOID Input, _In_ PVOID ExtraInfo) |
__os_arm64x_x64_jump |
Wird in signaturlosen Adjustern und anderen Thunks verwendet, die einen Aufruf direkt an eine andere Funktion weiterleiten (jmp), die eine beliebige Signatur haben kann, und so die mögliche Anwendung des richtigen Thunks auf das eigentliche Ziel verschieben |
Argumente:x9: Ziel für einen SprungAlle Parameterregister bleiben erhalten (weitergeleitet) |
Thunks
Thunks sind die Low-Level-Mechanismen zur Unterstützung von ARM64EC- und x64-Funktionen, die einander aufrufen. Es gibt zwei Arten: Eingabe-Thunks für die Eingabe ARM64EC Funktionen und Ausgabe-Thunks zum Aufrufen von x64-Funktionen.
Eingabe-Thunk und intrinsische Eingabe-Thunks: x64 zu ARM64EC Funktionsaufruf
Um x64-Aufrufer zu unterstützen, wenn eine C/C++-Funktion als ARM64EC kompiliert wird, generiert die Toolkette einen einzelnen Eingabe-Thunk, der aus ARM64EC Computercode besteht. Systeminterne haben einen eigenen Eingabe-Thunk. Alle anderen Funktionen teilen einen Eingabe-Thunk mit allen Funktionen, die über eine übereinstimmende Aufrufkonvention, Parameter und Rückgabetyp verfügen. Der Inhalt des Thunk hängt von der Aufrufkonvention der C/C++-Funktion ab.
Neben der Behandlung von Parametern und der Absenderadresse überbrückt der Thunk die Unterschiede bei der Volatilität zwischen ARM64EC und x64-Vektorregistern, die durch ARM64EC Vektorregisterzuordnung verursacht werden:
| ARM64EC Registrier | x64-Register | ARM64EC Anrufkonvention | Aufrufkonvention bei ARM64-Systemen | Aufrufkonvention bei x64-Systemen |
|---|---|---|---|---|
v6-v15 |
xmm6-xmm15 |
flüchtig, aber im Eingabe-Thunk gespeichert und wiederhergestellt (x64 bis ARM64EC) | veränderliche oder teilweise volatile obere 64 Bits | Nicht flüchtig |
Der Eingabe-Thunk führt die folgenden Aktionen aus:
| Parameteranzahl | Stapelverwendung |
|---|---|
| 0–4 | Speichert ARM64EC v6 und v7 im vom Anrufer zugewiesenen HeimbereichDa der Angerufene ARM64EC ist, der nicht über den Begriff eines Heimbereichs verfügt, werden die gespeicherten Werte nicht überschrieben. Weist dem Stapel zusätzliche 128 Bytes zu und speichert ARM64EC v8 bis v15. |
| 5-8 |
x4 = 5. Parameter aus dem Stapelx5 = 6. Parameter aus dem Stapelx6 = 7. Parameter aus dem Stapelx7 = 8. Parameter aus dem StapelWenn der Parameter SIMD ist, werden stattdessen die v4-v7 Register verwendet |
| 9+ | Ordnet AlignUp(NumParams - 8 , 2) * 8 Bytes im Stapel zu. *Kopiert die 9. und verbleibenden Parameter in diesen Bereich |
* Das Ausrichten des Werts an einer geraden Zahl garantiert, dass der Stapel auf 16 Byte ausgerichtet bleibt
Wenn die Funktion einen ganzzahligen 32-Bit-Parameter akzeptiert, darf der Thunk nur 32 Bit anstelle der vollständigen 64 Bits des übergeordneten Registers pushen.
Als Nächstes verwendet der Thunk eine ARM64-Anweisung bl, um die ARM64EC-Funktion aufzurufen. Nachdem die Funktion zurückgegeben wurde, gibt der Thunk folgendes zurück:
- Rückgängigmachen aller Stapelzuweisungen
- Ruft das
__os_arm64x_dispatch_retEmulator-Hilfsprogramm auf, um die x64-Rücksprungadresse abzurufen und die x64-Emulation fortzusetzen.
Abgangs-Thunk: ARM64EC nach x64-Funktionsaufruf
Für jeden Aufruf, den eine ARM64EC C/C++-Funktion an möglichen x64-Code macht, generiert die MSVC-Toolchain einen Ausstiegsthunken. Der Inhalt des Thunks hängt von den Parametern des x64-Callee ab und davon, ob der Callee die standardmäßige Aufrufkonvention oder __vectorcall verwendet. Der Compiler ruft diese Informationen aus einer Funktionsdeklaration für den Angerufenen ab.
Zuerst verschiebt der Thunk die Absenderadresse, die sich im ARM64EC lr Register befindet, und einen Dummy 8-Byte-Wert, um sicherzustellen, dass der Stapel auf 16 Byte ausgerichtet ist. Zweitens behandelt der Thunk die Parameter:
| Parameteranzahl | Stapelverwendung |
|---|---|
| 0–4 | Ordnet 32 Byte Home Space auf dem Stapel zu |
| 5-8 | Weist AlignUp(NumParams - 4, 2) * 8 mehr Bytes höher auf dem Stapel zu. * Kopiert den 5. und alle nachfolgenden Parameter aus ARM64EC x4-x7 in diesen zusätzlichen Bereich |
| 9+ | Kopiert die 9. und verbleibenden Parameter in den zusätzlichen Leerraum |
* Das Ausrichten des Werts an einer geraden Zahl garantiert, dass der Stapel auf 16 Bytes ausgerichtet bleibt.
Drittens ruft der Thunk die __os_arm64x_dispatch_call_no_redirect Emulatorhilfsfunktion auf, um den x64-Emulator aufzurufen, um die x64-Funktion auszuführen. Der Anruf muss eine blr x16 Anweisung sein (glücklicherweise ist x16 ein veränderliches Register). Eine blr x16 Anweisung ist erforderlich, da der x64-Emulator diese Anweisung als Hinweis analysiert.
Die x64-Funktion versucht in der Regel, mithilfe einer x64-ret-Anweisung zum Emulatorhilfsprogramm zurückzukehren. An diesem Punkt erkennt der x64-Emulator, dass er sich in ARM64EC Code befindet. Anschließend wird der vorherige 4-Byte-Hinweis gelesen, der als ARM64-blr x16-Anweisung auftritt. Da dieser Hinweis darauf hinweist, dass sich die Absenderadresse in diesem Hilfsprogramm befindet, springt der Emulator direkt zu dieser Adresse.
Die x64-Funktion kann eine beliebige Sprunganweisung verwenden, um zum Emulator-Hilfsprogramm zurückzukehren, einschließlich x64 jmp und call. Der Emulator behandelt diese Szenarien ebenfalls.
Wenn der Helfer dann wieder zum Thunk zurückkehrt, geht der Thunk wie folgt vor:
- Rückgängigmachen aller Stapelzuweisungen
- Entfernen des ARM64EC
lr-Registers - Ausführung einer ARM64-Anweisung
ret lr.
ARM64EC Funktionsnamendekorierung
Ein ARM64EC-Funktionsname erhält nach jeder sprachspezifischen Dekoration eine zusätzliche sekundäre Dekoration. Für Funktionen mit C-Verknüpfung (ob als C oder mithilfe von extern "C" kompiliert) wird dem Namen eine # vorangestellt. Für C++-dekorierte Funktionen wird ein $$h Tag in den Namen eingefügt.
foo => #foo
?foo@@YAHXZ => ?foo@@$$hYAHXZ
__vectorcall
Die ARM64EC Toolkette unterstützt __vectorcall derzeit nicht. Der Compiler gibt einen Fehler aus, wenn er die __vectorcall Verwendung mit ARM64EC erkennt.
Siehe auch
Grundlegendes zu ARM64EC ABI- und Assemblycode
Häufige Probleme bei der Migration von Microsoft C++ ARM
Dekorierte Namen