Funktionen und Stack: Unterschied zwischen den Versionen
Die Seite wurde neu angelegt: „Funktionen und Stack In diesem Kapitel werden wir uns mit der Erstellung und Verwendung von Funktionen im ARM64-Assembler beschäftigen. Insbesondere werden wir uns mit den folgenden Themen befassen: Funktion aufrufen und Rückkehr Funktionsparameter und Rückgabewerte Verwendung des Stacks für lokale Variablen und Funktionsaufrufe Regeln für das Aufrufen von Funktionen (AAPCS) Funktion aufrufen und Rückkehr Eine Funktion im ARM64-Assembler wird dur…“ |
KKeine Bearbeitungszusammenfassung |
||
| Zeile 1: | Zeile 1: | ||
In diesem Kapitel werden wir uns mit der Erstellung und Verwendung von Funktionen im ARM64-Assembler beschäftigen. Insbesondere werden wir uns mit den folgenden Themen befassen: | In diesem Kapitel werden wir uns mit der Erstellung und Verwendung von Funktionen im ARM64-Assembler beschäftigen. Insbesondere werden wir uns mit den folgenden Themen befassen: | ||
| Zeile 7: | Zeile 5: | ||
Verwendung des Stacks für lokale Variablen und Funktionsaufrufe | Verwendung des Stacks für lokale Variablen und Funktionsaufrufe | ||
Regeln für das Aufrufen von Funktionen (AAPCS) | Regeln für das Aufrufen von Funktionen (AAPCS) | ||
Funktion aufrufen und Rückkehr | |||
== Funktion aufrufen und Rückkehr == | |||
Eine Funktion im ARM64-Assembler wird durch das Setzen eines Labels deklariert und kann mit dem Befehl bl (Branch with Link) aufgerufen werden. Der bl-Befehl speichert die Rücksprungadresse in das Register lr (Link Register, auch bekannt als x30), wodurch die Funktion nach ihrem Abschluss dorthin zurückkehren kann. | Eine Funktion im ARM64-Assembler wird durch das Setzen eines Labels deklariert und kann mit dem Befehl bl (Branch with Link) aufgerufen werden. Der bl-Befehl speichert die Rücksprungadresse in das Register lr (Link Register, auch bekannt als x30), wodurch die Funktion nach ihrem Abschluss dorthin zurückkehren kann. | ||
Beispiel: | Beispiel: | ||
<syntaxhighlight lang="asm"> | |||
.global _start | .global _start | ||
| Zeile 26: | Zeile 25: | ||
mov x0, #0 // Setze x0 auf 0, als Beispiel | mov x0, #0 // Setze x0 auf 0, als Beispiel | ||
ret // Kehre zur Rücksprungadresse zurück | ret // Kehre zur Rücksprungadresse zurück | ||
</syntaxhighlight> | |||
Funktionsparameter und Rückgabewerte | == Funktionsparameter und Rückgabewerte == | ||
In ARM64-Assembler werden Funktionsparameter in den Registern x0 bis x7 übergeben. Rückgabewerte werden üblicherweise in x0 zurückgegeben. | In ARM64-Assembler werden Funktionsparameter in den Registern x0 bis x7 übergeben. Rückgabewerte werden üblicherweise in x0 zurückgegeben. | ||
Beispiel: | Beispiel: | ||
<syntaxhighlight lang="asm"> | |||
.global _start | .global _start | ||
| Zeile 46: | Zeile 46: | ||
add x0, x0, x1 // Addiere x0 (10) und x1 (20), Ergebnis in x0 (30) | add x0, x0, x1 // Addiere x0 (10) und x1 (20), Ergebnis in x0 (30) | ||
ret // Kehre zurück | ret // Kehre zurück | ||
</syntaxhighlight> | |||
Verwendung des Stacks für lokale Variablen und Funktionsaufrufe | == Verwendung des Stacks für lokale Variablen und Funktionsaufrufe == | ||
Der Stack wird verwendet, um lokale Variablen zu speichern und den aktuellen Kontext bei verschachtelten Funktionsaufrufen zu sichern. Dies geschieht mit den Befehlen stp (store pair) und ldp (load pair), die Paare von Registern auf dem Stack speichern und wiederherstellen können. | Der Stack wird verwendet, um lokale Variablen zu speichern und den aktuellen Kontext bei verschachtelten Funktionsaufrufen zu sichern. Dies geschieht mit den Befehlen stp (store pair) und ldp (load pair), die Paare von Registern auf dem Stack speichern und wiederherstellen können. | ||
Beispiel: | Beispiel: | ||
<syntaxhighlight lang="asm"> | |||
.global _start | .global _start | ||
| Zeile 69: | Zeile 69: | ||
ldp x29, x30, [sp], #16 // Lade x29 und x30 vom Stack zurück | ldp x29, x30, [sp], #16 // Lade x29 und x30 vom Stack zurück | ||
ret // Kehre zurück | ret // Kehre zurück | ||
</syntaxhighlight> | |||
Problem des "LR" bei verschachtelten Funktionsaufrufen | === Problem des "LR" bei verschachtelten Funktionsaufrufen === | ||
Bei verschachtelten Funktionsaufrufen (eine Funktion ruft eine andere auf) muss das lr-Register gesichert werden, um sicherzustellen, dass die Rücksprungadresse korrekt erhalten bleibt. Dies geschieht typischerweise durch das Speichern von lr auf dem Stack bei jedem Funktionsaufruf. | Bei verschachtelten Funktionsaufrufen (eine Funktion ruft eine andere auf) muss das lr-Register gesichert werden, um sicherzustellen, dass die Rücksprungadresse korrekt erhalten bleibt. Dies geschieht typischerweise durch das Speichern von lr auf dem Stack bei jedem Funktionsaufruf. | ||
Beispiel: | Beispiel: | ||
<syntaxhighlight lang="asm"> | |||
.global _start | .global _start | ||
| Zeile 98: | Zeile 98: | ||
ldp x29, x30, [sp], #16 | ldp x29, x30, [sp], #16 | ||
ret | ret | ||
</syntaxhighlight> | |||
Regeln für das Aufrufen von Funktionen (AAPCS) | == Regeln für das Aufrufen von Funktionen (AAPCS) == | ||
Die ARM Architecture Procedure Call Standard (AAPCS) legt Regeln für das Aufrufen von Funktionen fest, um die Interoperabilität zwischen verschiedenen Code-Modulen sicherzustellen. | Die ARM Architecture Procedure Call Standard (AAPCS) legt Regeln für das Aufrufen von Funktionen fest, um die Interoperabilität zwischen verschiedenen Code-Modulen sicherzustellen. | ||
Wichtige Regeln des AAPCS | === Wichtige Regeln des AAPCS === | ||
Parameterübergabe: Die ersten acht Parameter werden in den Registern x0 bis x7 übergeben. Weitere Parameter werden auf dem Stack übergeben. | * Parameterübergabe: Die ersten acht Parameter werden in den Registern x0 bis x7 übergeben. Weitere Parameter werden auf dem Stack übergeben. | ||
Rückgabewerte: Rückgabewerte werden in x0 und x1 zurückgegeben, abhängig von der Größe des Rückgabewerts. | * Rückgabewerte: Rückgabewerte werden in x0 und x1 zurückgegeben, abhängig von der Größe des Rückgabewerts. | ||
Callee-saved Register: Register x19 bis x29 müssen von der aufgerufenen Funktion gesichert und wiederhergestellt werden. Register x0 bis x18 und x30 (LR) können von der Funktion frei verwendet werden. | * Callee-saved Register: Register x19 bis x29 müssen von der aufgerufenen Funktion gesichert und wiederhergestellt werden. Register x0 bis x18 und x30 (LR) können von der Funktion frei verwendet werden. | ||
Stack Alignment: Der Stack muss immer auf eine 16-Byte-Grenze ausgerichtet sein. | * Stack Alignment: Der Stack muss immer auf eine 16-Byte-Grenze ausgerichtet sein. | ||
Beispiel für eine Funktion, die sich an AAPCS hält: | Beispiel für eine Funktion, die sich an AAPCS hält: | ||
<syntaxhighlight lang="asm"> | |||
global _start | global _start | ||
| Zeile 131: | Zeile 131: | ||
ldp x29, x30, [sp], #16 // Lade x29 und x30 vom Stack zurück | ldp x29, x30, [sp], #16 // Lade x29 und x30 vom Stack zurück | ||
ret // Kehre zur Rücksprungadresse zurück | ret // Kehre zur Rücksprungadresse zurück | ||
</syntaxhighlight> | |||
Version vom 3. April 2025, 13:02 Uhr
In diesem Kapitel werden wir uns mit der Erstellung und Verwendung von Funktionen im ARM64-Assembler beschäftigen. Insbesondere werden wir uns mit den folgenden Themen befassen:
Funktion aufrufen und Rückkehr Funktionsparameter und Rückgabewerte Verwendung des Stacks für lokale Variablen und Funktionsaufrufe Regeln für das Aufrufen von Funktionen (AAPCS)
Funktion aufrufen und Rückkehr
Eine Funktion im ARM64-Assembler wird durch das Setzen eines Labels deklariert und kann mit dem Befehl bl (Branch with Link) aufgerufen werden. Der bl-Befehl speichert die Rücksprungadresse in das Register lr (Link Register, auch bekannt als x30), wodurch die Funktion nach ihrem Abschluss dorthin zurückkehren kann.
Beispiel:
.global _start
_start:
mov x0, #10 // Setze x0 auf 10
bl my_function // Rufe my_function auf
// Weiterer Code nach der Rückkehr von my_function
mov x8, #93 // exit system call
svc 0 // system call
my_function:
// Funktion beginnt hier
mov x0, #0 // Setze x0 auf 0, als Beispiel
ret // Kehre zur Rücksprungadresse zurück
Funktionsparameter und Rückgabewerte
In ARM64-Assembler werden Funktionsparameter in den Registern x0 bis x7 übergeben. Rückgabewerte werden üblicherweise in x0 zurückgegeben.
Beispiel:
.global _start
_start:
mov x0, #10 // Parameter 1: 10
mov x1, #20 // Parameter 2: 20
bl add_numbers // Rufe add_numbers auf
// Das Ergebnis (30) ist jetzt in x0
mov x8, #93 // exit system call
svc 0 // system call
add_numbers:
add x0, x0, x1 // Addiere x0 (10) und x1 (20), Ergebnis in x0 (30)
ret // Kehre zurück
Verwendung des Stacks für lokale Variablen und Funktionsaufrufe
Der Stack wird verwendet, um lokale Variablen zu speichern und den aktuellen Kontext bei verschachtelten Funktionsaufrufen zu sichern. Dies geschieht mit den Befehlen stp (store pair) und ldp (load pair), die Paare von Registern auf dem Stack speichern und wiederherstellen können.
Beispiel:
.global _start
_start:
mov x0, #10 // Parameter 1: 10
mov x1, #20 // Parameter 2: 20
bl add_numbers_with_stack // Rufe add_numbers_with_stack auf
// Das Ergebnis (30) ist jetzt in x0
mov x8, #93 // exit system call
svc 0 // system call
add_numbers_with_stack:
stp x29, x30, [sp, #-16]! // Speichere x29 (FP) und x30 (LR) auf dem Stack
mov x29, sp // Setze den Frame-Pointer
add x0, x0, x1 // Addiere x0 (10) und x1 (20), Ergebnis in x0 (30)
ldp x29, x30, [sp], #16 // Lade x29 und x30 vom Stack zurück
ret // Kehre zurück
Problem des "LR" bei verschachtelten Funktionsaufrufen
Bei verschachtelten Funktionsaufrufen (eine Funktion ruft eine andere auf) muss das lr-Register gesichert werden, um sicherzustellen, dass die Rücksprungadresse korrekt erhalten bleibt. Dies geschieht typischerweise durch das Speichern von lr auf dem Stack bei jedem Funktionsaufruf.
Beispiel:
.global _start
_start:
mov x0, #10
mov x1, #20
bl outer_function
mov x8, #93
svc 0
outer_function:
stp x29, x30, [sp, #-16]!
mov x29, sp
bl inner_function
ldp x29, x30, [sp], #16
ret
inner_function:
stp x29, x30, [sp, #-16]!
mov x29, sp
add x0, x0, x1
ldp x29, x30, [sp], #16
ret
Regeln für das Aufrufen von Funktionen (AAPCS)
Die ARM Architecture Procedure Call Standard (AAPCS) legt Regeln für das Aufrufen von Funktionen fest, um die Interoperabilität zwischen verschiedenen Code-Modulen sicherzustellen.
Wichtige Regeln des AAPCS
- Parameterübergabe: Die ersten acht Parameter werden in den Registern x0 bis x7 übergeben. Weitere Parameter werden auf dem Stack übergeben.
- Rückgabewerte: Rückgabewerte werden in x0 und x1 zurückgegeben, abhängig von der Größe des Rückgabewerts.
- Callee-saved Register: Register x19 bis x29 müssen von der aufgerufenen Funktion gesichert und wiederhergestellt werden. Register x0 bis x18 und x30 (LR) können von der Funktion frei verwendet werden.
- Stack Alignment: Der Stack muss immer auf eine 16-Byte-Grenze ausgerichtet sein.
Beispiel für eine Funktion, die sich an AAPCS hält:
global _start
_start:
mov x0, #10
mov x1, #20
bl add_numbers // Aufruf der Funktion
mov x8, #93 // exit system call
svc 0 // system call
add_numbers:
stp x29, x30, [sp, #-16]! // Speichere x29 (FP) und x30 (LR) auf dem Stack
mov x29, sp // Setze den Frame-Pointer
stp x19, x20, [sp, #-16]! // Speichere x19 und x20 (callee-saved Register)
mov x19, x0 // Benutze x19 als temporäres Register
mov x20, x1 // Benutze x20 als temporäres Register
add x0, x19, x20 // Addiere x0 und x1 und speichere das Ergebnis in x0
ldp x19, x20, [sp], #16 // Lade x19 und x20 vom Stack zurück
ldp x29, x30, [sp], #16 // Lade x29 und x30 vom Stack zurück
ret // Kehre zur Rücksprungadresse zurück