Assemblersprache - Variablen

Variablen sind die Grundeinheiten zum Speichern von Daten in einem Programm. Das Definieren und Verwenden von Variablen in der Assemblersprache ist näher an der zugrunde liegenden Hardware als in höheren Programmiersprachen; Sie müssen die Größe, den Typ und das Speicherlayout von Variablen direkt steuern.


Konzept der Variablen in Assembler

In der Assemblersprache isteine Variableim Wesentlichen ein benannter Speicherort im Speicher.

Im Gegensatz zu höheren Programmiersprachen haben Assemblervariablen keine automatische Typprüfung – ein Label ist nur ein Alias für eine Speicheradresse, und Sie können es in jeder beliebigen Größe lesen oder schreiben.

NASM stellt drei Sektionen zur Verfügung, um verschiedene Arten von Variablen zu speichern:.data(initialisiert),.bss(nicht initialisiert) und.rodata(schreibgeschützt).


Definieren initialisierter Variablen in der Sektion .data

Verwenden Sie die Direktiven DB, DW, DD, DQ, DT, um Variablen verschiedener Größen zu definieren:

DirektiveDatenmengeBedeutungBeispiel
DB1 ByteByte definierenflag db 1
DW2 ByteWort (Word) definierencount dw 1000
DD4 ByteDoppelwort (Doubleword) definierenprice dd 9999
DQ8 BytesQuadwort (Quadword) definierenbig_val dq 0x1234567890ABCDEF
DT10 BytesZehn Bytes definierenext_val dt 3.14

Beispiel

; Dateipfad: variables_data.asm
; Demonstriert das Definieren verschiedener Variablen in der .data-Sektion

section .data
    ; Byte-Variable
    status db 1                 ; 1 Byte, Wert 1
    grade db 'A'                ; 1 Byte, Zeichen 'A' = 0x41

    ; Wort-Variable (2 Bytes)
    year dw 2026                ; 2 Bytes, Wert 2026

    ; Doppelwort-Variable (4 Bytes)
    salary dd 50000             ; 4 Bytes, Wert 50000

    ; Mehrbyte-Sequenz
    msg db 'Hello, example!', 0  ; Nullterminierte Zeichenkette (C-Stil)
    hex_bytes db 0x55, 0xAA, 0x00, 0xFF   ; Hexadezimale Byte-Sequenz

    ; Wiederholter Wert
    stars db 10 dup('*')        ; 10 Sternchen-Zeichen

    ; Mehrere Variablen mit Namen
    x dd 10
    y dd 20
    z dd 30

section .text
    global _start

_start:
    ; Variablenwerte in Register einlesen
    mov al, [status]            ; al = 1 (1 Byte lesen)
    mov ax, [year]              ; ax = 2026 (2 Bytes lesen)
    mov eax, [salary]           ; eax = 50000 (4 Bytes lesen)

    ; Variablenwerte ändern
    mov byte [status], 0        ; status = 0
    mov dword [x], 100          ; x = 100

    mov eax, 1
    mov ebx, 0
    int 0x80

Verwenden Sie[variable name]Stellen Sie beim Zugriff auf eine Variable sicher, dass die Anzahl der gelesenen/geschriebenen Bytes mit der für die Variable definierten Größe übereinstimmt. Verwenden Siemov al, [status]um 1 Byte zu lesen, verwenden Siemov eax, [salary]um 4 Bytes zu lesen. NASM überprüft, ob die Größen der Operanden übereinstimmen.


Reservieren von nicht initialisiertem Speicherplatz in der Sektion .bss

Verwenden Sie Direktiven wie RESB, RESW, RESD, um Speicherplatz zu reservieren (ohne zu initialisieren):

DirektiveReservierte GrößeBeispiel
RESBBytebuffer resb 256
RESWWort (2 Bytes)wbuf resw 100
RESDDoppelwort (4 Bytes)dbuf resd 50
RESQQuadwort (8 Bytes)qbuf resq 25

Beispiel

; Dateipfad: variables_bss.asm
; Demonstriert das Reservieren von Speicherplatz in der .bss-Sektion

section .bss
    input_buf resb 128          ; Einen 128-Byte-Eingabepuffer reservieren
    numbers resd 100            ; 100 Doppelwörter (400 Bytes) reservieren
    temp resb 1                 ; Eine temporäre 1-Byte-Variable reservieren

section .data
    prompt db 'Enter a number: '
    prompt_len equ $ - prompt

section .text
    global _start

_start:
    ; Eingabeaufforderung
    mov eax, 4
    mov ebx, 1
    mov ecx, prompt
    mov edx, prompt_len
    int 0x80

    ; Eingabe in den Puffer in der .bss-Sektion einlesen
    mov eax, 3
    mov ebx, 0
    mov ecx, input_buf           ; Den in der .bss-Sektion reservierten Speicherplatz verwenden
    mov edx, 128
    int 0x80

    ; Daten in das Zahlen-Array füllen
    mov dword [numbers], 42      ; numbers[0] = 42
    mov dword [numbers + 4], 100 ; numbers[1] = 100

    mov eax, 1
    mov ebx, 0
    int 0x80

Speicherlayout von Bytes, Wörtern und Doppelwörtern

x86 verwendetLittle-Endian (Little Endian)– das niedrigstwertige Byte wird an der niedrigsten Adresse gespeichert.

Wenn Sie beispielsweisevalue dd 0x12345678definieren, sieht das Speicherlayout wie folgt aus:

地址    :[value]  [value+1]  [value+2]  [value+3]
内容    :0x78     0x56       0x34       0x12

Beispiel

; Dateipfad: endianness.asm
; Demonstration der Little-Endian-Speicherung

section .data
    value dd 0x12345678        ; Doppelwort, 4 Bytes

section .text
    global _start

_start:
    ; Lesen derselben Variable in verschiedenen Größen
    mov eax, [value]            ; 4 Bytes lesen: eax = 0x12345678
    mov ax, [value]             ; 2 Bytes lesen: ax = 0x5678 (untere 2 Bytes)
    mov al, [value]             ; 1 Byte lesen: al = 0x78 (niedrigstes Byte)

    ; Little-Endian überprüfen: niedrigere Adressen speichern niederwertigere Bytes
    mov al, [value]             ; al = 0x78
    mov bl, [value + 1]         ; bl = 0x56
    mov cl, [value + 2]         ; cl = 0x34
    mov dl, [value + 3]         ; dl = 0x12

    mov eax, 1
    mov ebx, 0
    int 0x80

Initialisierung und Zugriff auf Variablen

In der Assemblersprache folgen Variablemationen dem Dreistufenmuster "Laden-Verarbeiten-Speichern":

Beispiel

; Dateipfad: var_operations.asm
; Demonstration des Dreistufenmusters von Variablenoperationen

section .data
    a dd 100
    b dd 200
    result dd 0

section .text
    global _start

_start:
    ; result = a + b
    ; Schritt 1: Laden
    mov eax, [a]                ; Lade a in eax
    ; Schritt 2: Verarbeiten
    add eax, [b]                ; eax = eax + b
    ; Schritt 3: Speichern
    mov [result], eax           ; Speichere das Ergebnis in result

    ; result = a * 2 - b
    mov eax, [a]
    imul eax, 2                 ; eax = a * 2
    sub eax, [b]                ; eax = eax - b
    mov [result], eax

    mov eax, 1
    mov ebx, 0
    int 0x80

Assembler unterstütztmov [result], [a] + [b]diese High-Level-Syntax nicht. Der x86-mov-Befehl kann nicht zwei Speicheroperanden gleichzeitig verwenden; er muss über ein Register als Vermittler laufen.


Variablengrößen-Operatoren

Wenn der Assembler die Operandengröße nicht ableiten kann, muss sie explizit angegeben werden:

Beispiel

; Verwende Größenoperatoren, um die Datengröße zu verdeutlichen

section .data
    var dd 0

section .text
    global _start

_start:
    ; Größenoperatoren: byte, word, dword, qword
    mov byte [var], 1           ; Schreibe 1 Byte
    mov word [var], 1000        ; Schreibe 2 Bytes
    mov dword [var], 999999     ; Schreibe 4 Bytes

    ; Wenn die Zielgröße klar ist (durch das Register bestimmt), kann sie weggelassen werden
    mov al, [var]               ; al ist 1 Byte, wird automatisch als byte gelesen
    mov ax, [var]               ; ax ist 2 Bytes, wird automatisch als word gelesen
    mov eax, [var]              ; eax ist 4 Bytes, wird automatisch als dword gelesen

    ; Die folgende Zeile führt jedoch zu einem Fehler (Größe ist mehrdeutig):
    ; mov [var], 1 ; Fehler! 1 könnte byte/word/dword sein
    ; Sie muss wie folgt geschrieben werden:
    mov dword [var], 1          ; Explizite Angabe von 4 Bytes

    mov eax, 1
    mov ebx, 0
    int 0x80
Weitere Erweiterungen