← SEARCHABLE ARCHIVE
Assembly · 2026-08-15

x86-64-Funktionsaufrufe und ABIs in der Praxis

Argumente, gesicherte Register, Stackausrichtung und Unwinding unter System V und Windows x64

INTERACTIVE READING MODE →

x86-64-Funktionsaufrufe und ABIs in der Praxis

Diese Blogartikel sind als Lehrmaterial gedacht. Dieser Artikel vergleicht System V AMD64 und Microsoft x64. Kernel, Syscalls, vectorcall und Toolchain-Erweiterungen benötigen eigene Zieldokumentation.

Der CPU-Befehl call speichert lediglich eine Rücksprungadresse und überträgt die Kontrolle. Das ABI legt fest, wo Argumente und Ergebnisse liegen, wer Register sichert, wie der Stack ausgerichtet und ein Frame abgewickelt wird.

ISA, Calling Convention und ABI

  • Die ISA definiert Befehle und Registerverhalten.
  • Die Calling Convention definiert Argumente, Ergebnisse, gesicherten Zustand und Stackverantwortung.
  • Das ABI umfasst zusätzlich Typlayout, Objektformat, Symbole, Relocations und Unwind-Regeln.

extern "C" steuert C++-Sprachbindung und Name Mangling, macht aus einer Windows-Funktion aber keine System-V-Funktion.

Vergleich

PunktSystem V AMD64Microsoft x64
Integerargumenterdi,rsi,rdx,rcx,r8,r9Position 1–4: rcx,rdx,r8,r9
FP-Argumentevor allem xmm0–xmm7Position 1–4: xmm0–xmm3
Integerergebnisraxrax
FP-Ergebnisxmm0xmm0
Caller-Bereichkein Shadow Space32 Byte Shadow Space
Red Zone128 Byte für geeignete User-Space-Leaf-Funktionenkeine
wichtige nonvolatile GPRrbx,rbp,r12–r15,rspzusätzlich rdi,rsi
nonvolatile XMMkeineuntere 128 Bit von xmm6–xmm15

Aggregate, Vektoren, variadische Funktionen und versteckte Rückgabezeiger brauchen weitere Klassifikation.

Caller-saved und Callee-saved

Volatile Register dürfen sich über einen Aufruf ändern; der Caller sichert einen benötigten Livewert. Verwendet der Callee ein nonvolatile Register, muss er es restaurieren.

push rbx
mov rbx, rcx
; use rbx
pop rbx
ret

Sichern bedeutet nicht zwingend push. Ein unbenutztes Register braucht keine Sicherung, und ein Stackslot mit mov ist ebenfalls möglich.

System-V- und Windows-Aufruf

System V:

mov edi, 10
mov esi, 20
mov edx, 30
call combine
; result in rax

Windows x64:

sub rsp, 40
mov ecx, 10
mov edx, 20
mov r8d, 30
call combine
add rsp, 40

32 Byte sind der vom Caller bereitgestellte Shadow Space. Weitere 8 Byte ergeben unter Berücksichtigung der von call abgelegten Rücksprungadresse eine typische Ausrichtung. Der Shadow Space wird auch bei weniger als vier Argumenten reserviert.

C-long ist im System-V-LP64-Modell üblicherweise 64 Bit, im Windows-LLP64-Modell aber 32 Bit. x64 erzwingt keine einheitliche Quellsprachbreite.

Stackausrichtung braucht einen Zeitpunkt

Unterscheiden Sie:

  1. unmittelbar vor call beim Caller;
  2. Callee-Eintritt nach dem Ablegen der Rücksprungadresse;
  3. nach dem Prolog;
  4. unmittelbar vor einem nested call.

Die Modulo-Regel eines Zeitpunkts auf einen anderen anzuwenden erzeugt die typische 8-Byte-Verwirrung. Windows x64 verlangt außerhalb von Prolog und Epilog 16-Byte-Ausrichtung von rsp.

Red Zone und Unwind

Geeignete System-V-User-Space-Leaf-Funktionen dürfen 128 Byte unter rsp verwenden. Diese Annahme gilt nicht über einen nested Call, unter Windows, im Kernel oder bei deaktivierter Red Zone.

Windows-Non-Leaf-Funktionen müssen realen Prolog und Unwind-Metadaten in Einklang halten.

Work PROC FRAME
    push rbx
    .pushreg rbx
    sub rsp, 32
    .allocstack 32
    .endprolog
    ; body
    add rsp, 32
    pop rbx
    ret
Work ENDP

Die Direktiven führen die Befehle nicht aus, sondern beschreiben sie. Eine Abweichung kann normale Rückkehrtests bestehen und trotzdem Exceptions, Profiler und Stack Walking zerstören.

Stack- und FP-Argumente

Windows übergibt Positionen ab fünf auf dem Stack. Der Offset hängt davon ab, ob er sich auf den Callee-Eintritt oder den Zustand nach dem Prolog bezieht. [rsp+40] darf ohne Zeitpunkt nicht pauschal als fünftes Argument betrachtet werden.

void f(int a, double b, int c, float d);

Unter Windows ergibt sich ungefähr a -> rcx, b -> xmm1, c -> r8, d -> xmm3. Gezählt werden Argumentpositionen, nicht nur FP-Argumente.

Variadisch, Aggregate und versteckte Parameter

Für printf-artige Aufrufe gelten Zusatzregeln:

  • System V übermittelt in al Informationen zu Vektorregisterargumenten.
  • Microsoft x64 dupliziert variadische FP-Werte in das entsprechende Integerregister.
  • C Default Argument Promotions machen aus float ein double.

System V klassifiziert Aggregate in Eightbytes und kann sie auf Integer- und SSE-Register aufteilen. Windows übergibt bestimmte Größen als Wert und andere über einen Zeiger auf ein Caller-Temporary. Handgeschriebene ASM-Grenzen sollten feste skalare Breiten, einfache extern "C"-Funktionen und Assertions für sizeof, alignof, offsetof bevorzugen. Caller- und Callee-Disassembly müssen beide geprüft werden.

Große Rückgabestrukturen können einen versteckten Rückgabezeiger hinzufügen und alle sichtbaren Argumente scheinbar um eine Position verschieben.

Tail Call

wrapper:
    ; Argumente für target anordnen
    jmp target

Wenn die ABI-Bedingungen passen, ersetzt der Compiler ein abschließendes call plus ret durch jmp; target kehrt direkt zum ursprünglichen Caller zurück.

Debug-Reihenfolge

  1. Verwenden Caller und Callee dieselbe Architektur und dasselbe ABI?
  2. Stimmen Symbol und Sprachbindung?
  3. Liegen Bits und Typen unmittelbar vor call an den richtigen Stellen?
  4. Auf welchen rsp-Zeitpunkt bezieht sich ein Stackoffset?
  5. Stimmen Ausrichtung und Windows Shadow Space?
  6. Werden alle geänderten nonvolatile Register auf jedem Pfad restauriert?
  7. Entsprechen Windows-Frame-Direktiven dem echten Prolog?
  8. Wird das Ergebnis mit korrekter Breite aus rax oder aus xmm0 gelesen?

Zusammenfassung

call und ret sind nur das Hardwaregerüst. System V verwendet sechs wichtige Integerargumentregister und eine Red Zone. Microsoft x64 verwendet vier positionsbasierte Registerplätze, 32 Byte Shadow Space, nonvolatile XMM-Register und strenge Unwind-Regeln. Beweisen Sie den Vertrag mit Caller-/Callee-Disassembly, Grenztests und Stack Walking.

Offizielle Quellen