====== Lyx – ABI & Calling Conventions ======
Die ABI (Application Binary Interface) legt fest, wie Funktionen auf Binärebene kommunizieren: welche Register Argumente tragen, wie der Stack aufgebaut ist, wer Register sichert und wie der Rückgabewert transportiert wird. Lyx folgt den nativen Konventionen der jeweiligen Zielplattform, um Kompatibilität mit Betriebssystem-Syscalls und C-Bibliotheken ohne Wrapper zu gewährleisten.
Dieses Wissen ist notwendig für:
* **FFI-Grenzen** – C-Funktionen korrekt aufrufen und exportieren
* **Inline-Assembly** – Register-Belegung vor und nach ''unsafe''-Blöcken
* **Debugging** – Stack-Traces und Disassemblies interpretieren
* **Safety-Nachweis** – ''--call-graph''-Reports bei DO-178C-Zertifizierung
===== 1. Datentyp-Größen & Alignment =====
Alle Typen folgen ihrer natürlichen Ausrichtung (Alignment = Größe, maximal 8 Byte). Das gilt auf allen drei unterstützten Architekturen.
^ Typ ^ Größe (Byte) ^ Alignment ^ Registerklasse ^
| ''bool'' | 1 | 1 | Integer (GPR), Wert 0 oder 1 |
| ''int8'' / ''uint8'' | 1 | 1 | Integer (GPR) |
| ''int16'' / ''uint16'' | 2 | 2 | Integer (GPR) |
| ''int32'' / ''uint32'' | 4 | 4 | Integer (GPR) |
| ''int64'' / ''uint64'' | 8 | 8 | Integer (GPR) |
| ''isize'' / ''usize'' | 8 | 8 | Integer (GPR) |
| ''f32'' | 4 | 4 | Float (FPU/SIMD) |
| ''f64'' | 8 | 8 | Float (FPU/SIMD) |
| ''qbool'' | 8 | 8 | **Float (FPU)** – wie f64 |
| ''pchar'' / ''%%^T%%'' | 8 | 8 | Integer (GPR) – Pointer = int64 |
| ''char'' | 1 | 1 | Integer (GPR) |
> **qbool in der ABI:**
> Obwohl ''qbool'' logisch wie ein ''bool'' wirkt, wird er als ''f64'' behandelt. Wahrscheinlichkeitswerte fließen direkt durch die Floating-Point-Einheiten – ohne GPR-zu-FPU-Konvertierung.
==== Struct-Alignment ====
Structs werden so ausgerichtet, dass jedes Feld sein natürliches Alignment erfüllt. Der Compiler fügt Padding-Bytes ein:
type Example = struct {
a: uint8; // Offset 0, 1 Byte
// 7 Byte Padding
b: int64; // Offset 8, 8 Byte
c: uint32; // Offset 16, 4 Byte
// 4 Byte Padding
};
// Gesamt: 24 Byte
Mit ''@packed'' entfällt das Padding (wichtig für Hardware-Register-Maps und Protokoll-Frames):
@packed
type PackedExample = struct {
a: uint8; // Offset 0
b: int64; // Offset 1
c: uint32; // Offset 9
};
// Gesamt: 13 Byte – kein Padding
→ Details: [[lyx_-_programmiersprache:sprache:ffi|FFI – @packed und Struct-Layout]]
===== 2. x86_64 – System V AMD64 (Linux / macOS) =====
Die Standard-Konvention auf Linux und macOS. Lyx verwendet sie für alle Nicht-Windows-Targets.
==== Integer-Register ====
Zuordnung der Integer-Register nach x86-64 System V ABI:
^ Zweck ^ Register ^ Gesichert von ^
| Argument 1 | RDI | Aufrufer (Caller-saved) |
| Argument 2 | RSI | Aufrufer |
| Argument 3 | RDX | Aufrufer |
| Argument 4 | RCX | Aufrufer |
| Argument 5 | R8 | Aufrufer |
| Argument 6 | R9 | Aufrufer |
| Argument 7+ | Stack | Aufrufer |
| Rückgabewert (primär) | RAX | Aufrufer |
| Rückgabewert (sekundär) | RDX | Aufrufer |
| Scratch (temporär) | R10, R11 | Aufrufer |
| Callee-saved | RBX, RBP, R12–R15 | Aufgerufener |
==== Float-Register (XMM / YMM) ====
Zuordnung der Floating-Point-Register:
^ Zweck ^ Register ^
| Float-Argumente 1–8 | XMM0 – XMM7 |
| Float-Rückgabewert | XMM0 |
| Caller-saved | XMM0 – XMM15 |
==== Prolog / Epilog (x86_64) ====
Standard-Funktionsrahmen bei x86_64:
; Funktionsprolog (Lyx-generiert)
push rbp ; Sichert alten Frame-Pointer (Callee-saved)
mov rbp, rsp ; Neuer Frame-Pointer
sub rsp, N ; Platz für lokale Variablen (N = nächstes Vielfaches von 16)
; … Funktionskörper …
; Funktionsepilog
mov rsp, rbp ; Stack-Pointer wiederherstellen
pop rbp ; Frame-Pointer wiederherstellen
ret ; Springt zur Adresse auf dem Stack (von 'call' abgelegt)
==== Konkretes Beispiel ====
fn Add(a: int64, b: int64): int64 {
return a + b;
}
Generierter Assembler:
Add:
push rbp
mov rbp, rsp
mov rax, rdi ; a kommt in RDI → ins Ergebnis-Register RAX
add rax, rsi ; b kommt in RSI → addieren
pop rbp
ret
==== Rekursion auf x86_64 ====
Bei rekursiven Aufrufen muss nichts extra gesichert werden – ''call'' legt die Rücksprungadresse automatisch auf den Stack. RBP wird im Prolog gesichert.
Factorial:
push rbp
mov rbp, rsp
cmp rdi, 1
jle .base
push rdi ; RDI sichern (Caller-saved, wird durch rekursiven call überschrieben)
dec rdi
call Factorial ; RDI = n-1
pop rdi ; RDI (= n) wiederherstellen
imul rax, rdi ; Ergebnis = n * Factorial(n-1)
jmp .done
.base:
mov rax, 1
.done:
pop rbp
ret
===== 3. x86_64 – Microsoft x64 (Windows) =====
Windows verwendet eine eigene Calling Convention. Der Hauptunterschied: nur vier Argument-Register, Shadow Space auf dem Stack.
==== Integer-Register ====
Zuordnung der Integer-Register nach x86-64 System V ABI:
^ Zweck ^ Register ^ Gesichert von ^
| Argument 1 | RCX | Aufrufer |
| Argument 2 | RDX | Aufrufer |
| Argument 3 | R8 | Aufrufer |
| Argument 4 | R9 | Aufrufer |
| Argument 5+ | Stack | Aufrufer |
| Rückgabewert | RAX | Aufrufer |
| Callee-saved | RBX, RBP, RDI, RSI, R12–R15 | Aufgerufener |
==== Float-Register ====
Zuordnung der Floating-Point-Register:
^ Zweck ^ Register ^
| Float-Argumente 1–4 | XMM0 – XMM3 |
| Float-Rückgabewert | XMM0 |
| Caller-saved | XMM0 – XMM5 |
| Callee-saved | XMM6 – XMM15 |
> **Wichtiger Unterschied zu System V:**
> Auf Windows sind XMM6–XMM15 **callee-saved**. Wenn Lyx-Code diese Register nutzt (z. B. für f64-Operationen), muss der generierte Prolog sie sichern. Der Lyx-Compiler erledigt das automatisch beim Windows-Target.
==== Shadow Space ====
Vor jedem Funktionsaufruf reserviert der Aufrufer **32 Byte Shadow Space** auf dem Stack – direkt unterhalb der Rücksprungadresse. Windows-API-Funktionen nutzen diesen Bereich intern zum Sichern von RCX, RDX, R8, R9.
; Windows-Aufruf: Funktion mit 2 Argumenten
sub rsp, 40 ; 32 Byte Shadow Space + 8 Byte Alignment
mov rcx, arg1 ; Argument 1
mov rdx, arg2 ; Argument 2
call SomeCFunction
add rsp, 40 ; Shadow Space freigeben
Lyx generiert den Shadow Space automatisch bei allen ''@extern''-Aufrufen unter Windows-Target.
==== @stdcall ====
''@stdcall'' ist die Aufrufkonvention älterer Win32-APIs (vor Vista weit verbreitet). Der wesentliche Unterschied: **Der Aufgerufene räumt den Stack auf** (nicht der Aufrufer).
@extern @stdcall
fn MessageBoxA(hwnd: int64, text: pchar, caption: pchar, flags: uint32): int32;
===== 4. ARM64 / AArch64 (AAPCS64) =====
ARM64 verwendet den AAPCS64-Standard (Procedure Call Standard for the Arm 64-bit Architecture). Dieser gilt auf Linux-ARM, Apple Silicon (macOS/iOS) und Embedded-ARM-Targets.
==== Integer-Register (X0–X30) ====
Zuordnung der Integer-Register nach x86-64 System V ABI:
^ Register ^ Alias ^ Zweck ^ Gesichert von ^
| X0–X7 | – | Argumente 1–8 / Rückgabewert 1–2 | Aufrufer |
| X8 | XR | Indirekter Ergebnis-Zeiger (große Structs) | Aufrufer |
| X9–X15 | – | Temporäre Register | Aufrufer |
| X16–X17 | IP0, IP1 | Intra-Procedure-Call Scratch | Aufrufer |
| X18 | PR | Platform-Register (OS-intern, nicht für Lyx) | – |
| X19–X28 | – | Callee-saved Register | Aufgerufener |
| X29 | FP | Frame-Pointer | Aufgerufener |
| X30 | LR | Link-Register (Rücksprungadresse) | Aufgerufener |
| SP | – | Stack-Pointer (16-Byte-Aligned) | – |
==== Float-/SIMD-Register (V0–V31) ====
^ Register ^ Zweck ^ Gesichert von ^
| V0–V7 | Float-Argumente / Float-Rückgabewert | Aufrufer |
| V8–V15 | Callee-saved | Aufgerufener |
| V16–V31 | Temporäre SIMD-Register | Aufrufer |
==== Prolog / Epilog (ARM64) ====
; ARM64 Funktionsprolog
stp x29, x30, [sp, #-16]! ; Frame-Pointer (x29) und Link-Register (x30) sichern
; '!' = Pre-Decrement: SP wird zuerst um 16 verringert
mov x29, sp ; Neuen Frame-Pointer setzen
; … Funktionskörper …
; ARM64 Funktionsepilog
ldp x29, x30, [sp], #16 ; FP und LR wiederherstellen; SP += 16
ret ; Springt zu Adresse in X30
> **Häufigster ARM64-Bug bei Rekursion:**
> Das Link-Register X30 wird beim ''bl''-Befehl (Branch with Link) mit der Rücksprungadresse des **aktuellen** Aufrufs überschrieben. Ohne ''stp x29, x30'' am Anfang verliert die Funktion ihre eigene Rücksprungadresse, sobald sie eine andere Funktion aufruft. Das führt zu einem Absturz beim ''ret''.
==== Konkretes Beispiel: Drei-Argument-Funktion ====
fn Clamp(val: int64, lo: int64, hi: int64): int64 {
if (val < lo) { return lo; }
if (val > hi) { return hi; }
return val;
}
Clamp:
; val → X0, lo → X1, hi → X2
stp x29, x30, [sp, #-16]!
mov x29, sp
cmp x0, x1
bge .check_hi
mov x0, x1 ; return lo
b .done
.check_hi:
cmp x0, x2
ble .done
mov x0, x2 ; return hi
.done:
ldp x29, x30, [sp], #16
ret
==== Ergebnis-Register bei großen Structs ====
Structs bis 16 Byte werden in X0–X1 zurückgegeben (zwei 8-Byte-Hälften). Größere Structs: Der Aufrufer reserviert Platz und übergibt den Zeiger in X8 (Indirect Result Register). Der Aufgerufene schreibt das Ergebnis dorthin.
type BigResult = struct { a: int64; b: int64; c: int64; }; // 24 Byte
fn GetResult(): BigResult {
return BigResult { a: 1, b: 2, c: 3 };
// Compiler: Aufrufer reserviert 24 Byte, Adresse in X8
// Aufgerufener schreibt nach [X8]
}
===== 5. RISC-V64 (RV64GC) =====
Für RISC-V nutzt Lyx die offizielle RISC-V calling convention (psABI, Integer + FP extension).
==== Register-Übersicht ====
^ ABI-Name ^ Reg.-Nr. ^ Zweck ^ Gesichert von ^
| ''zero'' | x0 | Konstante 0 (hardwired) | – |
| ''ra'' | x1 | Return Address (Rücksprungadresse) | Aufgerufener |
| ''sp'' | x2 | Stack Pointer | Aufgerufener |
| ''gp'' | x3 | Global Pointer (GOT-Zugriff) | – |
| ''tp'' | x4 | Thread Pointer (TLS) | – |
| ''t0–t2'' | x5–x7 | Temporäre Register | Aufrufer |
| ''s0 / fp'' | x8 | Saved Register / Frame Pointer | Aufgerufener |
| ''s1'' | x9 | Saved Register | Aufgerufener |
| ''a0–a7'' | x10–x17 | Argumente / Rückgabewerte (a0–a1) | Aufrufer |
| ''s2–s11'' | x18–x27 | Saved Register | Aufgerufener |
| ''t3–t6'' | x28–x31 | Temporäre Register | Aufrufer |
==== Float-Register (F-Extension) ====
^ ABI-Name ^ Zweck ^ Gesichert von ^
| ''fa0–fa7'' | Float-Argumente / Rückgabe | Aufrufer |
| ''fs0–fs11'' | Saved Float-Register | Aufgerufener |
| ''ft0–ft11'' | Temporäre Float-Register | Aufrufer |
==== Prolog / Epilog (RISC-V64) ====
; RISC-V64 Funktionsprolog
addi sp, sp, -16 ; Stack-Pointer verringern
sd ra, 8(sp) ; Rücksprungadresse sichern
sd s0, 0(sp) ; Frame-Pointer sichern
addi s0, sp, 16 ; Neuen Frame-Pointer setzen
; … Funktionskörper …
; RISC-V64 Funktionsepilog
ld ra, 8(sp) ; Rücksprungadresse wiederherstellen
ld s0, 0(sp) ; Frame-Pointer wiederherstellen
addi sp, sp, 16 ; Stack freigeben
ret ; = jalr x0, ra, 0
Ähnlich wie ARM64: ''ra'' muss im Prolog gesichert werden, bevor eine andere Funktion aufgerufen wird.
===== 6. Stack-Layout & Alignment =====
Alle drei Architekturen verlangen ein **16-Byte-Alignment** des Stack-Pointers zum Zeitpunkt eines Funktionsaufrufs. Der Lyx-Compiler stellt dies im Prolog sicher.
==== Stack-Frame-Struktur (x86_64, System V) ====
Höhere Adressen (Richtung Basis)
┌──────────────────────────────────┐
│ Argument 8+ (vom Aufrufer) │ ← RSP vor dem 'call'
├──────────────────────────────────┤
│ Rücksprungadresse (von 'call') │
├──────────────────────────────────┤ ← RBP zeigt hier
│ Gesicherter alter RBP │
├──────────────────────────────────┤
│ Lokale Variable 1 │
│ Lokale Variable 2 │
│ … │
├──────────────────────────────────┤
│ Padding (für 16-Byte-Alignment) │
└──────────────────────────────────┘ ← RSP (aktuelle Position)
Niedrigere Adressen (Stack wächst ↓)
==== @integrity – Canary-Bytes ====
In Modulen mit ''@integrity'' oder ''@redundant'' fügt der Lyx-Compiler zusätzliche **Canary-Bytes** zwischen Stack-Frames ein. Diese werden beim Epilog geprüft; eine Änderung signalisiert einen Pufferüberlauf oder Bit-Flip.
@integrity(mode: scrubbed)
@dal(B)
fn ProcessFrame(data: ^uint8) {
var buf: [128]uint8;
// Compiler: legt Canary-Wert oberhalb von 'buf', prüft ihn im Epilog
}
===== 7. Rückgabewerte =====
Konventionen für Rückgabewerte nach ABI:
==== Primitive Typen ====
^ Typ ^ x86_64 ^ ARM64 ^ RISC-V64 ^
| ''int8''…''int64'', Pointer | RAX | X0 | a0 |
| ''f32'', ''f64'', ''qbool'' | XMM0 | V0 | fa0 |
| Zweiter Rückgabewert | RDX | X1 | a1 |
==== Tupel-Rückgabe ====
Lyx unterstützt Tupel-Rückgaben: ''(int64, bool)''. Beide Werte werden in den zwei primären Rückgabe-Registern transportiert:
fn Divide(a: int64, b: int64): (int64, bool) {
if (b = 0) { return (0, false); }
return (a / b, true);
}
; x86_64: RAX = Quotient, RDX = ok (0 oder 1)
; ARM64: X0 = Quotient, X1 = ok
; RISC-V: a0 = Quotient, a1 = ok
==== Große Structs (> 16 Byte) ====
Structs über 16 Byte werden nicht in Registern zurückgegeben. Der Aufrufer alloziert den Speicher und übergibt einen versteckten Zeiger:
^ Architektur ^ Zeiger-Register ^
| x86_64 (System V) | RDI (erstes Argument – verschiebt alle anderen um +1) |
| ARM64 | X8 (Indirect Result Register – kein Argument verschoben) |
| RISC-V64 | a0 (erstes Argument – verschiebt alle anderen um +1) |
===== 8. Variadic Functions (@variadic) =====
Variadische Funktionen (C-''printf''-Stil) erfordern in System V, dass ''AL'' (lower byte of RAX) die Anzahl der genutzten XMM-Register enthält, bevor die Funktion aufgerufen wird.
@extern @variadic
fn printf(fmt: pchar): int32;
; x86_64 System V: printf("Wert: %d\n", 42)
mov rdi, fmt_str ; Format-String
mov rsi, 42 ; Erstes variadisches Argument
xor eax, eax ; AL = 0 (keine XMM-Register genutzt)
call printf
Auf Windows (Microsoft x64) entfällt die AL-Konvention; variadische Argumente folgen den normalen Argument-Registern (RCX, RDX, R8, R9, dann Stack).
===== 9. Systemaufruf-Konvention (Syscalls) =====
Syscalls nutzen eine eigene Konvention und umgehen die normale Calling Convention. ''std.os'' und ''std.fs'' kapseln diese Aufrufe.
^ Aspekt ^ x86_64 (Linux) ^ ARM64 (Linux) ^ RISC-V64 (Linux) ^
| Syscall-Nummer | RAX | X8 | a7 |
| Argument 1 | RDI | X0 | a0 |
| Argument 2 | RSI | X1 | a1 |
| Argument 3 | RDX | X2 | a2 |
| Argument 4 | R10 | X3 | a3 |
| Argument 5 | R8 | X4 | a4 |
| Argument 6 | R9 | X5 | a5 |
| Rückgabewert | RAX | X0 | a0 |
| Instruktion | ''syscall'' | ''svc #0'' | ''ecall'' |
// std.os kapselt Syscalls – direkter Einsatz nur in unsafe + FFI:
unsafe {
// write(1, msg, len) → Syscall Nr. 1 auf x86_64
var result: int64;
// ... inline asm oder std.os.Write() verwenden
}
===== 10. Plattform-Vergleich: Wichtigste Unterschiede =====
^ Merkmal ^ System V (Linux/macOS) ^ Microsoft x64 ^ ARM64 (AAPCS64) ^ RISC-V64 ^
| Argument-Register (Int) | 6 (RDI,RSI,RDX,RCX,R8,R9) | 4 (RCX,RDX,R8,R9) | 8 (X0–X7) | 8 (a0–a7) |
| Argument-Register (Float) | 8 (XMM0–XMM7) | 4 (XMM0–XMM3) | 8 (V0–V7) | 8 (fa0–fa7) |
| Rückgabe-Register | RAX (+RDX) | RAX | X0 (+X1) | a0 (+a1) |
| Float-Rückgabe | XMM0 | XMM0 | V0 | fa0 |
| Shadow Space | Nein | **32 Byte** | Nein | Nein |
| Callee-saved XMM | Keine | XMM6–XMM15 | V8–V15 | fs0–fs11 |
| Rücksprung-Adresse | Stack (''call'') | Stack (''call'') | X30 (LR) | x1 (ra) |
| Stack-Alignment | 16 Byte | 16 Byte | 16 Byte | 16 Byte |
| Struct > 16 Byte | RDI (arg 0) | Stack | X8 (IR) | a0 (arg 0) |
===== 11. Auswirkung auf Lyx-Code =====
Praktische Auswirkungen der ABI-Regeln auf Lyx-Programmcode:
==== Funktionen mit vielen Parametern ====
Mehr als 6 (System V) / 4 (Windows) / 8 (ARM64/RISC-V) Integer-Argumente gehen auf den Stack – mit Aufruf-Overhead. Die Lyx-Empfehlung: Struct-Pointer übergeben.
// Schlecht: viele Parameter → Stack-Overflow-Risiko bei @flight_crit
fn ProcessData(a: int64, b: int64, c: int64, d: int64, e: int64, f: int64, g: int64) { ... }
// Besser: Struct-Pointer – ein Register, kein Stack-Argument
type DataParams = struct { a: int64; b: int64; c: int64; d: int64; e: int64; f: int64; g: int64; };
fn ProcessData(p: ^DataParams) { ... }
==== float vs. int in Argumentposition ====
Werden Float- und Integer-Argumente gemischt, belegen sie **separate** Registerbänke und blockieren sich nicht gegenseitig:
fn Mix(i: int64, f: f64, j: int64): f64 {
// x86_64 System V: i→RDI, f→XMM0, j→RSI
// ARM64: i→X0, f→V0, j→X1
return f * (i as f64) + (j as f64);
}
==== @export und C-Kompatibilität ====
Mit ''@export'' erzeugt der Lyx-Compiler ein C-kompatibles Symbol ohne Name-Mangling. Die Konvention folgt der Plattform-ABI:
@export
pub fn lyx_add(a: int64, b: int64): int64 {
return a + b;
}
// Verwendung aus C:
extern long lyx_add(long a, long b);
long result = lyx_add(3, 4); // 7
===== 12. ABI in Safety-Code =====
Bei DO-178C-Zertifizierung muss die ABI-Konformität nachgewiesen werden. Der ''--call-graph''-Pass erzeugt einen Bericht über alle Funktionsaufrufe und deren Register-Belegung:
lyxc --call-graph --provenance --target arm64 main.lyx
Call-Graph-Auszug:
ProcessFlightData(val: f64)
Plattform: ARM64 (AAPCS64)
Argumente: val → V0 (f64, Float-Register)
Rückgabe: X0 (int64)
Callee-saved genutzt: X19, X20
Sichere Register: X19, X20 korrekt gesichert (stp/ldp im Prolog/Epilog)
unsafe-Blöcke: keine
@redundant-Variablen: heading (TMR-gesichert)
✅ ABI-konform
===== 13. macOS x86_64 – Mach-O Backend-Besonderheiten =====
Der ''--target=macosx64''-Backend erzeugt **Mach-O**-Binaries statt ELF. Die Calling Convention ist identisch mit System V AMD64 (Abschnitt 2), aber es gibt plattformspezifische Unterschiede im generierten Maschinencode und in den Syscall-Nummern.
==== _start-Stub und Helper-Offsets ====
Der macOS-''_start''-Stub ist **79 Bytes** lang (Linux: 65 Bytes). Die drei eingebetteten Helper-Symbole liegen an exakt denselben Offset-Positionen wie auf Linux:
^ Symbol ^ Offset im Binary ^
| ''strlen'' | Byte 79 |
| ''printstr'' | Byte 94 |
| ''printint'' | Byte 120 |
Der ''rel32''-Patch für den ''call main''-Sprung verwendet Bytes **63–66** (nicht 49–52 wie bei ''CG_ARGC'' — ein kritischer Bug in der ersten Implementierung, der falsche Sprungziele erzeugte).
==== Mach-O Data-Section ====
''cg.data'' (Strings und VMT-Tabellen) wird **nach** dem Code-Segment in die Mach-O-Datei geschrieben. VMT-Zeiger, die für Linux-Basisadressen berechnet wurden, werden beim Schreiben auf die macOS-Ladeadresse umgerechnet (**VMT-Patching: Linux-Base → macOS-Base**).
==== Syscall-Nummern: macOS vs. Linux ====
macOS x86_64 verwendet andere Syscall-Nummern als Linux. Die folgende Tabelle zeigt die 9 Socket-Syscalls, die der Backend-Code anpasst:
^ Syscall ^ Linux x86_64 ^ macOS x86_64 ^
| ''socket'' | 41 | 97 |
| ''connect'' | 42 | 98 |
| ''bind'' | 49 | 104 |
| ''listen'' | 50 | 106 |
| ''accept'' | 43 | 30 |
| ''sendto'' | 44 | 133 |
| ''recvfrom'' | 45 | 29 |
| ''setsockopt'' | 54 | 105 |
| ''shutdown'' | 48 | 134 |
==== Plattformkonstanten ====
^ Konstante ^ Linux ^ macOS ^
| ''MAP_ANON'' | ''0x20'' | ''0x1002'' |
Der Unterschied betrifft alle ''mmap''-Aufrufe für anonyme Speicherzuordnungen (''alloc'', Heap, Stack-Extension). Ein falscher ''MAP_ANON''-Wert führt zu ''EINVAL'' beim Systemaufruf.
----
**Weiterführende Seiten:**
* [[lyx_-_programmiersprache:sprache:ffi|FFI – @extern, @export, @packed, Callbacks]]
* [[lyx_-_programmiersprache:sprache:pointer-inlining|Pointer & Inlining – unsafe, @volatile, @inline]]
* [[lyx_-_programmiersprache:sprache:memory-management|Memory Management – Stack-Layout, @stack_limit]]
* [[lyx_-_programmiersprache:sprache:rekursion|Rekursion – Prolog/Epilog bei rekursiven Aufrufen]]
* [[lyx_-_programmiersprache:tools:lyx-compiler-selbst-kompilieren|Compiler selbst kompilieren – Cross-Compilation-Targets]]
* [[lyx_-_programmiersprache:guides:do-178c|DO-178C – Call-Graph-Nachweis und ABI-Verifikation]]