Assemblersprache - Grundlegende Syntax
Dieses Kapitel stellt die Grundstruktur, Syntaxregeln und Schreibkonventionen von NASM-Assemblerprogrammen vor und hilft Ihnen, das Grundgerüst von Assemblercode zu verstehen.
Grundstruktur eines Assemblerprogramms
Ein vollständiges NASM-Assemblerprogramm besteht normalerweise aus den folgenden Teilen:
Beispiel
; Beispiel für eine grundlegende NASM-Programmstruktur
section .data ; Datenabschnitt: speichert initialisierte Daten
; Definieren Sie hier Variablen und Konstanten
msg db 'Hello, EXAMPLE!', 0xA
len equ $ - msg
section .bss ; BSS-Abschnitt: speichert uninitialisierte Daten
; Reservieren Sie hier Speicherplatz
buffer resb 64 ; Reserviere einen 64-Byte-Puffer
section .text ; Codeabschnitt: speichert ausführbare Anweisungen
global _start
_start:
; Schreiben Sie hier die Programmlogik
mov eax, 4
mov ebx, 1
mov ecx, msg
mov edx, len
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
| Bereich | Zweck | Eigenschaften |
|---|---|---|
.data | Speichert initialisierte globale Variablen und Konstanten | Größe und Inhalt werden zur Kompilierungszeit bestimmt, im ausführbaren Datei gespeichert |
.bss | Speichert uninitialisierte globale Variablen | Speicherplatz wird erst zur Laufzeit zugewiesen, belegt keine Größe der ausführbaren Datei |
.text | Speichert ausführbare Maschinenbefehle | Schreibgeschützt, enthält den gesamten Logikcode des Programms |
Mindestens
.textAbschnitte sind erforderlich, um ein gültiges Assemblerprogramm zu bilden. Wenn keine Daten vorhanden sind, kann der.dataund.bss-Abschnitt weggelassen werden.
Format der Assembleranweisung
Das allgemeine Format jeder Assembleranweisung ist:
[标签:] 指令助记符 [操作数1 [, 操作数2 [, 操作数3]]] [; 注释]
Erklärung der einzelnen Teile:
| Teil | Erforderlich? | Beschreibung |
|---|---|---|
| Label | Optional | Ein symbolischer Name, der eine Speicheradresse darstellt, endend mit einem Doppelpunkt |
| Befehlsmnemonic | Erforderlich | Wie mov, add, sub usw., teilt der CPU mit, was zu tun ist |
| Operand | Optional (einige Befehle haben keinen Operanden) | Das vom Befehl bearbeitete Datenobjekt kann ein Register, eine Speicheradresse oder ein unmittelbarer Wert sein |
| Kommentar | Optional | Beginnt mit einem Semikolon und geht bis zum Ende der Zeile |
Beispiel
; Nur Befehl, kein Operand
ret ; Rückkehr aus Subroutine
; Befehl + einzelner Operand
push eax ; Den Wert von eax auf den Stapel legen
inc ecx ; Addiere 1 zu ecx
; Befehl + zwei Operanden (am häufigsten)
mov eax, 42 ; Kopiere 42 in das eax-Register
add ebx, ecx ; ebx = ebx + ecx
; Mit einer Marke (Label)
loop_start: ; Label: markiert den Beginn der Schleife
dec ecx ; Subtrahiere 1 von ecx
jnz loop_start ; Wenn ecx nicht 0 ist, springe zurück zu loop_start
Kommentarkonventionen
NASM verwendet dasSemikolon (;), um Kommentare zu kennzeichnen; Inhalte ab dem Semikolon bis zum Ende der Zeile werden vom Assembler ignoriert.
Beispiel
; Berechne die Summe zweier Zahlen und gib das Ergebnis aus
mov eax, 10 ; Inline-Kommentar: schreibe 10 in eax
add eax, 20 ; Inline-Kommentar: addiere 20 zu eax, jetzt ist eax = 30
Kommentare sind im Assemblercode äußerst wichtig. Ohne Kommentare versteht selbst der Autor den Assemblercode nach ein paar Wochen möglicherweise nicht mehr. Machen Sie es sich zur Gewohnheit, für jeden Befehl einen Kommentar zu schreiben.
Regeln für die Benennung von Bezeichnern
Bezeichner (Labels, Variablennamen, Konstantennamen usw.) müssen den folgenden Regeln folgen:
| Regel | Beschreibung |
|---|---|
| Zulässige Zeichen | Buchstaben, Ziffern, Unterstrich _, Punkt ., Fragezeichen ?, @, $, # usw. |
| Startzeichen | Muss mit einem Buchstaben, Unterstrich, Punkt oder Fragezeichen beginnen; darf nicht mit einer Ziffer beginnen. |
| Groß-/Kleinschreibung | Standardmäßig groß-/kleinschreibungssensitiv (kann über Kompilierungsoptionen geändert werden) |
| Reservierte Wörter | Dürfen nicht denselben Namen haben wie Befehlsmneonics, Registernamen oder NASM-Schlüsselwörter. |
Beispiel
my_variable: ; Beginnt mit einem Buchstaben + Unterstrich
.loop_start: ; Beginnt mit einem Punkt (lokales Label)
?error_handler: ; Beginnt mit einem Fragezeichen
counter2: ; Buchstabe + Ziffer
; Ungültige Bezeichner (nur zur Referenz, nicht verwenden)
; 1st_value: ; Fehler: darf nicht mit einer Ziffer beginnen
; mov: ; Fehler: mov ist ein reserviertes Wort
; my-variable: ; Fehler: Bindestrich ist kein gültiges Zeichen
Pseudo-Anweisungen (Direktiven)
Direktivensind Befehle für den Assembler, keine Befehle für die CPU; sie steuern den Assemblierungsprozess und definieren Datenstrukturen.
| Direktiven | Zweck | Beispiel |
|---|---|---|
db | Byte definieren (1 Byte) | byte_val db 0x55 |
dw | Word definieren (2 Bytes) | word_val dw 0x1234 |
dd | Double Word definieren (4 Bytes) | dword_val dd 0x12345678 |
equ | Konstante definieren | MAX_SIZE equ 256 |
resb | Byte-Speicher reservieren | buffer resb 128 |
resw | Word-Speicher reservieren | wbuf resw 64 |
resd | Double-Word-Speicher reservieren | dbuf resd 32 |
%define | Makrodefinierte Konstante | %define COUNT 10 |
Schreibkonventionen
NASM unterscheidet bei Marken und Bezeichnern standardmäßig zwischen Groß- und Kleinschreibung.:
Beispiel
section .data
msg db 'EXAMPLE', 0 ; Variable msg definieren
section .text
global _start
_start:
mov eax, MSG ; Fehler: MSG und msg sind unterschiedlich (außer der Modus für Groß-/Kleinschreibung ist deaktiviert)
mov eax, msg ; Korrekt: msg stimmt genau mit der Definition überein
MOV EAX, 42 ; Syntaktisch korrekt: Befehlsschnitte sind unabhängig von Groß- und Kleinschreibung
mov eax, 42 ; Empfohlener Stil: Kleinbuchstaben für bessere Lesbarkeit verwenden
Befehlsschnitte und Registernamen sind unabhängig von Groß- und Kleinschreibung (
MOV、Mov、movgleicher Effekt), aber der empfohlene Stil ist durchgehend in Kleinbuchstaben.
Numerische Darstellung
NASM unterstützt die numerische Darstellung in mehreren Basen:
Beispiel
mov eax, 42 ; Dezimal: Zahl direkt schreiben
mov eax, 0x2A ; Hexadezimal: 0x-Präfix (empfohlener Stil)
mov eax, 2Ah ; Hexadezimal: h-Suffix
mov eax, 0o52 ; Oktal: 0o-Präfix
mov eax, 52o ; Oktal: o-Suffix
mov eax, 101010b ; Binär: b-Suffix
mov eax, 0b101010 ; Binär: 0b-Präfix
Empfohlen:
0xPräfix für Hexadezimal verwenden (z. B.0x2A), damit es weniger wahrscheinlich mit Marken verwechselt wird.
Ein vollständiges Syntaxbeispiel
Das folgende Programm verwendet die obigen Syntaxelemente umfassend, um die Summe von 1 bis 10 zu berechnen und auszugeben:
Beispiel
; 1+2+...+10 berechnen und das Ergebniszeichen ausgeben
section .data
result db 0 ; Berechnungsergebnis speichern (1 Byte)
newline db 0xA ; Zeilenumbruchzeichen
section .text
global _start
_start:
; Register und Variablen initialisieren
mov ecx, 10 ; Schleifenzähler: von 10 herunterzählen
mov eax, 0 ; eax speichert die akkumulierte Summe, anfangs 0
sum_loop: ; Schleifenstartmarke
add eax, ecx ; eax = eax + ecx
dec ecx ; ecx um 1 dekrementieren
jnz sum_loop ; Wenn ecx != 0, Schleife fortsetzen
; Zu diesem Zeitpunkt ist eax = 55 (10+9+...+1)
add eax, '0' ; Zahl in ASCII-Zeichen umwandeln ('0'=48, 55+48=103='g', falsch)
; Die eigentliche Demonstration erfordert eine komplexere Konvertierung, siehe spätere Kapitel
; Hier nur Ergebnisausgabe (vereinfachte Demonstration)
mov [result], al ; Akkumuliertes Ergebnis in result speichern
; Programm beenden
mov eax, 1
mov ebx, 0
int 0x80
Weitere ErweiterungenHinweis: Im obigen Beispiel ist das direkte Hinzufügen von '0' nur korrekt, wenn die Zahl im Bereich 0-9 liegt. Das Konvertieren von Zahlen mit zwei oder mehr Ziffern wird in späteren Kapiteln detailliert erläutert.