Aliase: Unterschied zwischen den Versionen
KKeine Bearbeitungszusammenfassung |
KKeine Bearbeitungszusammenfassung |
||
| Zeile 1: | Zeile 1: | ||
== Aliase == | == Was sind Aliase? == | ||
Ein **Alias** ist eine alternative Schreibweise für eine Instruktion – sozusagen ein **„freundlicher“ Name** für komplexere Maschinenbefehle. Aliase machen den Code **lesbarer und intuitiver**, verändern aber **nicht** den Maschinencode, der letztlich generiert wird. | |||
Beispiel: | |||
```asm | |||
mov x0, x1 | |||
``` | |||
Dieser Befehl existiert **nicht als eigener Maschinenbefehl**, sondern ist ein **Alias** für: | |||
```asm | |||
orr x0, x1, xzr | |||
``` | |||
Der Befehl `orr` (bitweises ODER) mit dem Wert `xzr` (Zero-Register) ergibt effektiv `mov`. | |||
--- | --- | ||
== Warum macht man das? == | |||
- **` | - **Lesbarkeit**: `mov x0, x1` ist leichter verständlich als `orr x0, x1, xzr`. | ||
- **Portabilität**: Viele Architekturen haben einen `mov`, und Entwickler erwarten diesen. | |||
- **Compilerfreundlich**: Auch Compiler wie `clang` oder `gcc` generieren „Alias-ähnlichen“ Code. | |||
- | --- | ||
== Was macht `objdump` daraus? == | |||
Beim Disassemblieren mit `objdump` oder `gdb` siehst du **immer den echten Maschinenbefehl**, nicht den Alias. | |||
```asm | |||
mov x0, x1 ; geschrieben im Assembler | |||
``` | |||
Ergibt in `objdump -d`: | |||
``` | |||
orr x0, x1, xzr | |||
``` | |||
⚠️ Das kann verwirrend sein, wenn du Quellcode und disassemblierten Code vergleichst! | |||
--- | --- | ||
== Was wird wirklich generiert? == | |||
Nehmen wir `mov x0, x1`: | |||
- Quelltext (Alias): | |||
```asm | |||
mov x0, x1 | |||
``` | |||
- Assembler-Expansion: | |||
```asm | |||
orr x0, x1, xzr | |||
``` | |||
- Maschinencode (Hex): | |||
```text | |||
0xaa0103e0 | |||
``` | |||
➡️ Ob du `mov x0, x1` oder `orr x0, x1, xzr` schreibst, ergibt **denselben Maschinencode**. | |||
--- | --- | ||
== Bekannte Aliase im ARM64-Assembler == | |||
| Alias | Entsprechender Instruktionscode | Beschreibung | | |||
|----------------|------------------------------------------------|------------------------------------------| | |||
| `mov x0, x1` | `orr x0, x1, xzr` | Kopiere Register | | |||
| `mov x0, #0` | `movz x0, #0` | Setze Register auf 0 | | |||
| `cmp x0, x1` | `subs xzr, x0, x1` | Vergleich über Subtraktion ohne Ergebnis | | |||
| `neg x0, x1` | `sub x0, xzr, x1` | Negation | | |||
| `nop` | `hint #0` | Kein-Operation (für Alignment etc.) | | |||
| `ret` | `br x30` | Rücksprung aus Funktion | | |||
| `b label` | `b label` (kein Alias) | Unbedingter Sprung | | |||
| `bl label` | `bl label` (kein Alias) | Sprung mit Link (Funktionsaufruf) | | |||
| `movk/movz/movn`| Literalladen in 16-Bit-Chunks | Register initialisieren mit Immediate | | |||
--- | --- | ||
== Warum ist das wichtig? == | |||
1. **Disassembler zeigen keine Aliase** → verwirrend bei Analyse. | |||
2. **Debugging wird leichter**, wenn man den echten Maschinenbefehl kennt. | |||
3. **Assemblerfehler** können entstehen, wenn man glaubt, `mov` sei ein „echter“ Befehl mit eigenen Regeln. | |||
--- | --- | ||
Hier ist ein einfaches Beispielprogramm in ARM64-Assembler mit typischen **Alias-Instruktionen**, das du kompilieren und mit `objdump` untersuchen kannst. Danach zeige ich dir, wie die `objdump`-Ausgabe dazu aussieht. | |||
--- | |||
== Beispiel: `alias_test.s` == | |||
```asm | |||
.section .text | |||
.global _start | |||
_start: | |||
// Alias: mov x0, x1 -> orr x0, x1, xzr | |||
mov x0, x1 | |||
// Alias: mov x2, #0 -> movz x2, #0 | |||
mov x2, #0 | |||
// Alias: cmp x0, x1 -> subs xzr, x0, x1 | |||
cmp x0, x1 | |||
// Alias: neg x3, x4 -> sub x3, xzr, x4 | |||
neg x3, x4 | |||
// Alias: nop -> hint #0 | |||
nop | |||
// Alias: ret -> br x30 | |||
ret | |||
``` | |||
--- | |||
=== Bauen und disassemblieren === | |||
```bash | |||
as alias_test.s -o alias_test.o | |||
ld alias_test.o -o alias_test | |||
objdump -d alias_test | |||
``` | |||
--- | |||
=== Beispielausgabe von `objdump -d alias_test` === | |||
```asm | |||
0000000000401000 <_start>: | |||
401000: aa0103e0 orr x0, x1, xzr | |||
401004: d2800002 movz x2, #0x0 | |||
401008: eb01001f subs xzr, x0, x1 | |||
40100c: cb040060 sub x3, xzr, x4 | |||
401010: d503201f nop | |||
401014: d65f03c0 ret | |||
``` | |||
Du siehst: | |||
| Quellcode Alias | Disassembler zeigt | Bedeutung | | |||
|----------------------|------------------------|---------------------------------------------| | |||
| `mov x0, x1` | `orr x0, x1, xzr` | Kopiere x1 nach x0 | | |||
| `mov x2, #0` | `movz x2, #0x0` | Setze x2 auf 0 | | |||
| `cmp x0, x1` | `subs xzr, x0, x1` | Vergleiche x0 mit x1 | | |||
| `neg x3, x4` | `sub x3, xzr, x4` | x3 = -x4 | | |||
| `nop` | `hint #0` | Kein Effekt | | |||
| `ret` | `ret` | Rücksprung über x30 | | |||
--- | |||
=== Weitere Analyse === | |||
Wenn du **keine Aliase im Disassembly** möchtest (d. h. nur „echte“ Instruktionen), kannst du `objdump` so verwenden: | |||
```bash | |||
objdump -d -M no-aliases alias_test | |||
``` | |||
Das zeigt dir, wie es **der CPU intern** wirklich vorliegt. | |||
Version vom 10. April 2025, 17:17 Uhr
Was sind Aliase?
Ein **Alias** ist eine alternative Schreibweise für eine Instruktion – sozusagen ein **„freundlicher“ Name** für komplexere Maschinenbefehle. Aliase machen den Code **lesbarer und intuitiver**, verändern aber **nicht** den Maschinencode, der letztlich generiert wird.
Beispiel:
```asm mov x0, x1 ```
Dieser Befehl existiert **nicht als eigener Maschinenbefehl**, sondern ist ein **Alias** für:
```asm orr x0, x1, xzr ```
Der Befehl `orr` (bitweises ODER) mit dem Wert `xzr` (Zero-Register) ergibt effektiv `mov`.
---
Warum macht man das?
- **Lesbarkeit**: `mov x0, x1` ist leichter verständlich als `orr x0, x1, xzr`. - **Portabilität**: Viele Architekturen haben einen `mov`, und Entwickler erwarten diesen. - **Compilerfreundlich**: Auch Compiler wie `clang` oder `gcc` generieren „Alias-ähnlichen“ Code.
---
Was macht `objdump` daraus?
Beim Disassemblieren mit `objdump` oder `gdb` siehst du **immer den echten Maschinenbefehl**, nicht den Alias.
```asm mov x0, x1 ; geschrieben im Assembler ```
Ergibt in `objdump -d`: ``` orr x0, x1, xzr ```
⚠️ Das kann verwirrend sein, wenn du Quellcode und disassemblierten Code vergleichst!
---
Was wird wirklich generiert?
Nehmen wir `mov x0, x1`:
- Quelltext (Alias):
```asm mov x0, x1 ```
- Assembler-Expansion:
```asm orr x0, x1, xzr ```
- Maschinencode (Hex):
```text 0xaa0103e0 ```
➡️ Ob du `mov x0, x1` oder `orr x0, x1, xzr` schreibst, ergibt **denselben Maschinencode**.
---
Bekannte Aliase im ARM64-Assembler
| Alias | Entsprechender Instruktionscode | Beschreibung | |----------------|------------------------------------------------|------------------------------------------| | `mov x0, x1` | `orr x0, x1, xzr` | Kopiere Register | | `mov x0, #0` | `movz x0, #0` | Setze Register auf 0 | | `cmp x0, x1` | `subs xzr, x0, x1` | Vergleich über Subtraktion ohne Ergebnis | | `neg x0, x1` | `sub x0, xzr, x1` | Negation | | `nop` | `hint #0` | Kein-Operation (für Alignment etc.) | | `ret` | `br x30` | Rücksprung aus Funktion | | `b label` | `b label` (kein Alias) | Unbedingter Sprung | | `bl label` | `bl label` (kein Alias) | Sprung mit Link (Funktionsaufruf) | | `movk/movz/movn`| Literalladen in 16-Bit-Chunks | Register initialisieren mit Immediate |
---
Warum ist das wichtig?
1. **Disassembler zeigen keine Aliase** → verwirrend bei Analyse. 2. **Debugging wird leichter**, wenn man den echten Maschinenbefehl kennt. 3. **Assemblerfehler** können entstehen, wenn man glaubt, `mov` sei ein „echter“ Befehl mit eigenen Regeln.
--- Hier ist ein einfaches Beispielprogramm in ARM64-Assembler mit typischen **Alias-Instruktionen**, das du kompilieren und mit `objdump` untersuchen kannst. Danach zeige ich dir, wie die `objdump`-Ausgabe dazu aussieht.
---
Beispiel: `alias_test.s`
```asm
.section .text .global _start
_start:
// Alias: mov x0, x1 -> orr x0, x1, xzr mov x0, x1
// Alias: mov x2, #0 -> movz x2, #0 mov x2, #0
// Alias: cmp x0, x1 -> subs xzr, x0, x1 cmp x0, x1
// Alias: neg x3, x4 -> sub x3, xzr, x4 neg x3, x4
// Alias: nop -> hint #0 nop
// Alias: ret -> br x30 ret
```
---
Bauen und disassemblieren
```bash as alias_test.s -o alias_test.o ld alias_test.o -o alias_test objdump -d alias_test ```
---
Beispielausgabe von `objdump -d alias_test`
```asm 0000000000401000 <_start>:
401000: aa0103e0 orr x0, x1, xzr 401004: d2800002 movz x2, #0x0 401008: eb01001f subs xzr, x0, x1 40100c: cb040060 sub x3, xzr, x4 401010: d503201f nop 401014: d65f03c0 ret
```
Du siehst:
| Quellcode Alias | Disassembler zeigt | Bedeutung | |----------------------|------------------------|---------------------------------------------| | `mov x0, x1` | `orr x0, x1, xzr` | Kopiere x1 nach x0 | | `mov x2, #0` | `movz x2, #0x0` | Setze x2 auf 0 | | `cmp x0, x1` | `subs xzr, x0, x1` | Vergleiche x0 mit x1 | | `neg x3, x4` | `sub x3, xzr, x4` | x3 = -x4 | | `nop` | `hint #0` | Kein Effekt | | `ret` | `ret` | Rücksprung über x30 |
---
Weitere Analyse
Wenn du **keine Aliase im Disassembly** möchtest (d. h. nur „echte“ Instruktionen), kannst du `objdump` so verwenden:
```bash objdump -d -M no-aliases alias_test ```
Das zeigt dir, wie es **der CPU intern** wirklich vorliegt.