Inhaltsverzeichnis

Lyx – ABI & Calling Conventions

Die ABI definiert, wie Funktionen auf Binärebene miteinander kommunizieren. Da Lyx ein nativer Compiler ist, folgt er den Standard-Konventionen der jeweiligen Zielplattform, um Kompatibilität mit System-Aufrufen (Syscalls) und externen Bibliotheken (Shared Objects/DLLs) zu gewährleisten.

1) Register-Belegung (x86_64)

Unter Linux und macOS folgt Lyx der System V AMD64 ABI. Unter Windows wird die Microsoft x64 Calling Convention genutzt.

Zweck System V (Linux/macOS) Microsoft x64 (Windows)
1. Argument RDI RCX
2. Argument RSI RDX
3. Argument RDX R8
4. Argument RCX R9
5. Argument R8 Stack
6. Argument R9 Stack
Rückgabewert RAX RAX

Hinweis: Weitere Argumente werden bei beiden Systemen über den Stack übergeben.

2) Register-Belegung (ARM64 / AArch64)

Für ARM64 (Linux & Apple Silicon) nutzt Lyx die Standard AAPCS64 (Procedure Call Standard).

Argumente 1-8: Register X0 bis X7.

Rückgabewert: Register X0.

Stack Pointer: SP (muss immer 16-Byte ausgerichtet sein).

Link Register: X30 (enthält die Rücksprungadresse nach einem bl).

3) Stack-Layout & Alignment

Lyx garantiert bei jedem Funktionsaufruf ein 16-Byte Alignment des Stacks. Dies ist besonders wichtig für:

SIMD-Instruktionen (SSE/AVX/NEON): Viele dieser Befehle stürzen ab, wenn die Daten nicht korrekt ausgerichtet sind.

Blatt-Funktionen (Leaf Functions): Funktionen, die keine weiteren Funktionen aufrufen, können den Stack-Pointer oft unverändert lassen, um Performance zu sparen.

Prolog & Epilog

Jede nicht-getunte Funktion in Lyx führt beim Eintritt einen Prolog aus:

push rbp          // Sichere alten Base-Pointer
mov rbp, rsp      // Setze neuen Base-Pointer
sub rsp, 32       // Reserviere Platz für lokale Variablen (Beispiel)

Beim Verlassen (return) sorgt der Epilog für die Wiederherstellung:

leave             // Entspricht mov rsp, rbp; pop rbp
ret               // Rücksprung

4) Interaktion mit C (extern)

Wenn du eine Funktion als extern deklarierst, verlässt sich Lyx darauf, dass die Ziel-Bibliothek die oben genannten Regeln einhält.

// Lyx weiß, dass 'printf' das erste Argument in RDI (Linux) erwartet
extern "libc.so.6" fn printf(format: pchar, val: int64): int32;
 
fn Main() {
printf("Wert: %d\n", 42);
}
 
Wichtig für Windows: Beim Aufruf von WinAPI-Funktionen reserviert Lyx automatisch den sogenannten Shadow Space (32 Byte auf dem Stack), den Windows-Funktionen zur Sicherung der Register RCX, RDX, R8 und R9 erwarten.

5) Datentyp-Größen in der ABI

Typ Größe (Bytes) Alignment
int8 / uint8 1 1
int32 / uint32 4 4
int64 / uint64 8 8
f64 (Float) 8 8 (XMM/Floating-Point Register)
pchar (Pointer) 8 8
bool 1 1

6) Besonderheit: QBool (Probabilistisch)

Der Datentyp qbool (Quantum Boolean) wird intern als f64 (8 Byte) behandelt, da er Wahrscheinlichkeitswerte zwischen 0.0 und 1.0 speichert. In Verzweigungen (if) wird er gegen einen internen Schwellenwert (Standard 0.5) oder einen Hardware-Zufallsgenerator (sofern vorhanden) geprüft.