Makros in Assembler: Unterschied zwischen den Versionen
Die Seite wurde neu angelegt: „== Makros == .macro Name übergabe1,übergabe2,... Beispiel: .macro speicher wert1,wert2 ldr x0,=\wert1 ldr x1,=\wert2 .endm .global _start _start: speicher buffer1,buffer2 ... .data buffer1: .fill 255,1,0 buffer2: .fill 255,1,0 Beim Aufruf "speicher" wird an dieser Stelle des Codes einfach das Makro eingesetzt. Das definieren des Makros erzeugt keinen Code!“ |
KKeine Bearbeitungszusammenfassung |
||
| (3 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
== Makros == | Makros sind ein mächtiges Werkzeug im Assembler, das die Wiederverwendung von Code erleichtert. Sie funktionieren ähnlich wie Funktionen in Hochsprachen, jedoch auf Quelltextebene – d. h. sie werden vom Assembler '''vor''' dem eigentlichen Assemblierungsvorgang expandiert. | ||
Beispiel: | == Was sind Makros? == | ||
.macro | |||
Ein Makro ist eine benannte Codevorlage, die beim Aufruf durch die entsprechende Makrodefinition ersetzt wird. Dadurch kann redundanter Code vermieden und die Lesbarkeit verbessert werden. | |||
ldr | |||
Makros werden mit den Direktiven <code>.macro</code> und <code>.endm</code> definiert. | |||
=== Syntax === | |||
<syntaxhighlight lang="asm"> | |||
.macro name [Parameter[, Parameter...]] | |||
; Anweisungen | |||
.endm | |||
</syntaxhighlight> | |||
=== Einfaches Beispiel === | |||
<syntaxhighlight lang="asm"> | |||
.macro save_regs reg1, reg2 | |||
str \reg1, [sp, #-16]! | |||
str \reg2, [sp, #-16]! | |||
.endm | |||
</syntaxhighlight> | |||
Aufruf: | |||
<syntaxhighlight lang="asm"> | |||
save_regs x0, x1 | |||
</syntaxhighlight> | |||
== Parameter in Makros == | |||
Makros können '''benannte Parameter''' enthalten, die beim Aufruf ersetzt werden. Parameter werden mit einem umgekehrten Schrägstrich (`\`) verwendet, um sie im Makro zu referenzieren. | |||
=== Beispiel mit drei Parametern === | |||
<syntaxhighlight lang="asm"> | |||
.macro add_and_store dest, src1, src2 | |||
add \dest, \src1, \src2 | |||
str \dest, [sp, #-16]! | |||
.endm | |||
</syntaxhighlight> | |||
Aufruf: | |||
<syntaxhighlight lang="asm"> | |||
add_and_store x3, x1, x2 | |||
</syntaxhighlight> | |||
== Makros mit Labels == | |||
Ein Problem bei Makros kann die Wiederverwendung von Labels sein. Labels innerhalb eines Makros sollten lokal sein, sonst kann es bei mehrfacher Verwendung zu Namenskonflikten kommen. | |||
=== Lösung: Lokale Labels verwenden === | |||
Verwende numerische Labels oder eindeutige Namen mit <code>\@</code>: | |||
<syntaxhighlight lang="asm"> | |||
.macro blink delay | |||
1: | |||
nop | |||
subs \delay, \delay, #1 | |||
bne 1b | |||
.endm | |||
</syntaxhighlight> | |||
Oder mit <code>\@</code> für eindeutige Labels: | |||
<syntaxhighlight lang="asm"> | |||
.macro wait_loop delay | |||
loop\@: | |||
subs \delay, \delay, #1 | |||
bne loop\@ | |||
.endm | |||
</syntaxhighlight> | |||
== Verschachtelte Makros und Bedingungen == | |||
Makros dürfen auch andere Makros aufrufen oder einfache Bedingungen enthalten: | |||
<syntaxhighlight lang="asm"> | |||
.macro print_val reg | |||
mov x0, \reg | |||
mov x8, #64 // write syscall | |||
svc #0 | |||
.endm | |||
</syntaxhighlight> | |||
== Bedingte Makro-Ersetzungen in GAS (GNU Assembler) == | |||
GNU <code>as</code> erlaubt '''präprozessorartige Bedingungen''' mit folgenden Direktiven: | |||
* <code>.if</code>, <code>.ifdef</code>, <code>.ifndef</code>, <code>.else</code>, <code>.elseif</code>, <code>.endif</code> | |||
* <code>.irp</code>, <code>.irpc</code>, <code>.rept</code> – für Wiederholungen | |||
* <code>.macro</code> – mit bedingten Code-Blöcken '''innerhalb''' der Makrodefinition | |||
== Beispiel: Bedingung basierend auf Parameterwert == | |||
<syntaxhighlight lang="asm"> | |||
.macro load_value reg, val | |||
.ifc \val, #0 | |||
mov \reg, xzr | |||
.else | |||
mov \reg, \val | |||
.endif | |||
.endm | |||
</syntaxhighlight> | |||
=== Erklärung: === | |||
* <code>.ifc A, B</code> prüft, ob '''die Strings''' A und B gleich sind | |||
* <code>.ifnc</code> prüft, ob sie '''nicht''' gleich sind | |||
=== Aufruf: === | |||
<syntaxhighlight lang="asm"> | |||
load_value x0, #0 // ergibt: mov x0, xzr | |||
load_value x1, #42 // ergibt: mov x1, #42 | |||
</syntaxhighlight> | |||
== Weitere Beispiele: == | |||
<syntaxhighlight lang="asm"> | |||
.macro set_direction pin, dir | |||
.ifc \dir, out | |||
// mache was für Ausgang | |||
.elseifc \dir, in | |||
// mache was für Eingang | |||
.else | |||
.error "Unbekannter Parameter bei set_direction" | |||
.endif | |||
.endm | |||
</syntaxhighlight> | |||
== Einschränkungen: == | |||
* Es handelt sich '''nicht''' um Laufzeitbedingungen, sondern '''Assemblerzeitbedingungen''' | |||
* Es ist nur ein '''Stringvergleich''' möglich, keine numerischen Bedingungen wie <code>if \param > 5</code> | |||
* Du kannst <code>.if</code>, <code>.ifc</code>, <code>.ifdef</code>, <code>.ifne</code>, <code>.ifeq</code> u.a. verwenden | |||
== Übersicht der Direktiven == | |||
{| class="wikitable" | |||
|- | |||
! Direktive !! Bedeutung | |||
|- | |||
| <code>.if expr</code> || Wenn `expr` ≠ 0 | |||
|- | |||
| <code>.ifeq expr</code> || Wenn `expr` = 0 | |||
|- | |||
| <code>.ifne expr</code> || Wenn `expr` ≠ 0 | |||
|- | |||
| <code>.ifc A, B</code> || Wenn A = B (String) | |||
|- | |||
| <code>.ifnc A, B</code> || Wenn A ≠ B | |||
|- | |||
| <code>.ifdef symbol</code> || Wenn Symbol definiert | |||
|- | |||
| <code>.ifndef symbol</code> || Wenn nicht definiert | |||
|- | |||
| <code>.else</code>, <code>.endif</code>, <code>.elseif</code> || wie in C | |||
|} | |||
== Tipps zur Makro-Programmierung == | |||
* Verwende eindeutige Labels innerhalb von Makros. | |||
* Teste Makros isoliert, bevor du sie mehrfach einsetzt. | |||
* Makros sind zur Compilezeit sichtbar – Fehler treten oft erst beim Expandieren auf. | |||
* Nutze `\@` für eindeutige IDs (z. B. für Labels). | |||
* Makros können nicht rekursiv aufgerufen werden (kein Call-Stack). | |||
== Nützliche Anwendungen von Makros == | |||
* Wiederholte Codeblöcke kapseln (z. B. Register sichern/wiederherstellen) | |||
* Debug-Ausgaben standardisieren | |||
* GPIO-Ansteuerung vereinfachen | |||
* Speicherzugriffe vereinheitlichen | |||
== Einschränkungen == | |||
* Keine Rückgabewerte | |||
* Keine Laufzeitparameterprüfung | |||
* Nur syntaktische Ersetzung – kein Kontrollfluss wie bei echten Funktionen | |||
== Praktische Makros == | |||
.macro push1 register | |||
str \register,[sp,#-16]! | |||
.endm | |||
.macro push2 register1,register2 | |||
stp \register1,\register2,[sp,#-16]! | |||
.endm | |||
.macro pop1 register | |||
ldr \register,[sp],#16 | |||
.endm | |||
.macro pop2 register1,register2 | |||
ldp \register1,\register2,[sp],#16 | |||
.endm | .endm | ||
== Zusammenfassung == | |||
Makros im ARM64-Assembler helfen dir dabei, deine Programme kürzer, wartbarer und verständlicher zu schreiben. Richtig eingesetzt, erhöhen sie die Produktivität erheblich – besonders bei Hardwarezugriffen, Systemaufrufen und Wiederholungen. | |||
Aktuelle Version vom 11. April 2025, 10:16 Uhr
Makros sind ein mächtiges Werkzeug im Assembler, das die Wiederverwendung von Code erleichtert. Sie funktionieren ähnlich wie Funktionen in Hochsprachen, jedoch auf Quelltextebene – d. h. sie werden vom Assembler vor dem eigentlichen Assemblierungsvorgang expandiert.
Was sind Makros?
Ein Makro ist eine benannte Codevorlage, die beim Aufruf durch die entsprechende Makrodefinition ersetzt wird. Dadurch kann redundanter Code vermieden und die Lesbarkeit verbessert werden.
Makros werden mit den Direktiven .macro und .endm definiert.
Syntax
.macro name [Parameter[, Parameter...]]
; Anweisungen
.endm
Einfaches Beispiel
.macro save_regs reg1, reg2
str \reg1, [sp, #-16]!
str \reg2, [sp, #-16]!
.endm
Aufruf:
save_regs x0, x1
Parameter in Makros
Makros können benannte Parameter enthalten, die beim Aufruf ersetzt werden. Parameter werden mit einem umgekehrten Schrägstrich (`\`) verwendet, um sie im Makro zu referenzieren.
Beispiel mit drei Parametern
.macro add_and_store dest, src1, src2
add \dest, \src1, \src2
str \dest, [sp, #-16]!
.endm
Aufruf:
add_and_store x3, x1, x2
Makros mit Labels
Ein Problem bei Makros kann die Wiederverwendung von Labels sein. Labels innerhalb eines Makros sollten lokal sein, sonst kann es bei mehrfacher Verwendung zu Namenskonflikten kommen.
Lösung: Lokale Labels verwenden
Verwende numerische Labels oder eindeutige Namen mit \@:
.macro blink delay
1:
nop
subs \delay, \delay, #1
bne 1b
.endm
Oder mit \@ für eindeutige Labels:
.macro wait_loop delay
loop\@:
subs \delay, \delay, #1
bne loop\@
.endm
Verschachtelte Makros und Bedingungen
Makros dürfen auch andere Makros aufrufen oder einfache Bedingungen enthalten:
.macro print_val reg
mov x0, \reg
mov x8, #64 // write syscall
svc #0
.endm
Bedingte Makro-Ersetzungen in GAS (GNU Assembler)
GNU as erlaubt präprozessorartige Bedingungen mit folgenden Direktiven:
.if,.ifdef,.ifndef,.else,.elseif,.endif.irp,.irpc,.rept– für Wiederholungen.macro– mit bedingten Code-Blöcken innerhalb der Makrodefinition
Beispiel: Bedingung basierend auf Parameterwert
.macro load_value reg, val
.ifc \val, #0
mov \reg, xzr
.else
mov \reg, \val
.endif
.endm
Erklärung:
.ifc A, Bprüft, ob die Strings A und B gleich sind.ifncprüft, ob sie nicht gleich sind
Aufruf:
load_value x0, #0 // ergibt: mov x0, xzr
load_value x1, #42 // ergibt: mov x1, #42
Weitere Beispiele:
.macro set_direction pin, dir
.ifc \dir, out
// mache was für Ausgang
.elseifc \dir, in
// mache was für Eingang
.else
.error "Unbekannter Parameter bei set_direction"
.endif
.endm
Einschränkungen:
- Es handelt sich nicht um Laufzeitbedingungen, sondern Assemblerzeitbedingungen
- Es ist nur ein Stringvergleich möglich, keine numerischen Bedingungen wie
if \param > 5 - Du kannst
.if,.ifc,.ifdef,.ifne,.ifequ.a. verwenden
Übersicht der Direktiven
| Direktive | Bedeutung |
|---|---|
.if expr |
Wenn `expr` ≠ 0 |
.ifeq expr |
Wenn `expr` = 0 |
.ifne expr |
Wenn `expr` ≠ 0 |
.ifc A, B |
Wenn A = B (String) |
.ifnc A, B |
Wenn A ≠ B |
.ifdef symbol |
Wenn Symbol definiert |
.ifndef symbol |
Wenn nicht definiert |
.else, .endif, .elseif |
wie in C |
Tipps zur Makro-Programmierung
- Verwende eindeutige Labels innerhalb von Makros.
- Teste Makros isoliert, bevor du sie mehrfach einsetzt.
- Makros sind zur Compilezeit sichtbar – Fehler treten oft erst beim Expandieren auf.
- Nutze `\@` für eindeutige IDs (z. B. für Labels).
- Makros können nicht rekursiv aufgerufen werden (kein Call-Stack).
Nützliche Anwendungen von Makros
- Wiederholte Codeblöcke kapseln (z. B. Register sichern/wiederherstellen)
- Debug-Ausgaben standardisieren
- GPIO-Ansteuerung vereinfachen
- Speicherzugriffe vereinheitlichen
Einschränkungen
- Keine Rückgabewerte
- Keine Laufzeitparameterprüfung
- Nur syntaktische Ersetzung – kein Kontrollfluss wie bei echten Funktionen
Praktische Makros
.macro push1 register str \register,[sp,#-16]! .endm .macro push2 register1,register2 stp \register1,\register2,[sp,#-16]! .endm .macro pop1 register ldr \register,[sp],#16 .endm .macro pop2 register1,register2 ldp \register1,\register2,[sp],#16 .endm
Zusammenfassung
Makros im ARM64-Assembler helfen dir dabei, deine Programme kürzer, wartbarer und verständlicher zu schreiben. Richtig eingesetzt, erhöhen sie die Produktivität erheblich – besonders bei Hardwarezugriffen, Systemaufrufen und Wiederholungen.