Assemblersprache - Arrays
Ein Array ist eine Sammlung von Daten desselben Typs, die zusammenhängend gespeichert sind. In Assembler ist ein Array ein zusammenhängender Speicherblock, und auf jedes Element wird über eine Basisadresse plus einen Offset zugegriffen.
Definition eines eindimensionalen Arrays
Beispiel
section .data
; Methode 1: Elemente einzeln auflisten
arr1 dd 10, 20, 30, 40, 50 ; Ein Array mit 5 Doppelwort-Elementen
; Methode 2: Mit dup initialisieren
arr2 dd 10 dup(0) ; 10 Doppelwörter, alle 0
; Methode 3: Byte-Array
bytes db 1, 2, 3, 4, 5, 6 ; 6 Bytes
; Methode 4: Zeichenarray (Zeichenkette)
chars db 'example', 0 ; 7 Bytes
; Array-Längenberechnung (zur Kompilierzeit)
arr1_len equ ($ - arr1) / 4 ; Anzahl der Elemente in einem Doppelwort-Array
arr2_len equ ($ - arr2) / 4
bytes_len equ ($ - bytes) ; Byte-Array, keine Division erforderlich
section .bss
; Uninitialisiertes Array
buffer resd 100 ; Speicherplatz für 100 Doppelwörter reservieren
Zugriff auf Array-Elemente
Beim Zugriff auf Array-Elemente wird der AdressierungsmodusBasis + Index × Elementgrößeverwendet:
Beispiel
; Lesen und Schreiben von Array-Elementen
section .data
nums dd 100, 200, 300, 400, 500 ; 5 Elemente
nums_len equ ($ - nums) / 4
section .text
global _start
_start:
; Zugriff auf das 0. Element (Index 0)
mov eax, [nums] ; eax = 100
; Zugriff auf das 2. Element (Index 2)
mov eax, [nums + 2 * 4] ; eax = nums[2] = 300
; 2 * 4 = 8, also ein Offset von 8 Bytes von nums
; Verwenden Sie ein Register als Index
mov esi, 3 ; Index = 3
mov eax, [nums + esi * 4] ; eax = nums[3] = 400
; Array-Elemente ändern
mov dword [nums + 4], 250 ; nums[1] = 250
; Das Array enthält nun: 100, 250, 300, 400, 500
; EBX als Basisregister verwenden
mov ebx, nums ; ebx = Array-Basisadresse
mov eax, [ebx + 4 * 4] ; eax = nums[4] = 500
mov eax, 1
mov ebx, 0
int 0x80
Hinweis:
[nums + esi * 4]Die Multiplikation mit 4 erfolgt, weil jedes Element 4 Bytes (Doppelwort) groß ist. Für ein Byte-Array (db) schreiben Sie es direkt als[arr + esi]; für ein Wort-Array (dw) schreiben Sie es als[arr + esi * 2]。
Array-Durchlauf
Beispiel
; Durchlaufen des Arrays und Berechnen der Summe
section .data
numbers dd 5, 10, 15, 20, 25, 30, 35, 40, 45, 50
count equ ($ - numbers) / 4 ; Anzahl der Elemente
section .text
global _start
_start:
mov ecx, count ; Schleifenzähler
mov esi, 0 ; Index (beginnend bei 0)
mov eax, 0 ; Akkumulierte Summe
sum_loop:
add eax, [numbers + esi * 4] ; Array-Elemente akkumulieren
inc esi ; Index + 1
loop sum_loop
; eax = 5+10+15+...+50 = 275
; Eine andere Durchlauftheorie: Verwendung eines Zeigers
mov ecx, count
mov ebx, numbers ; ebx zeigt auf den Anfang des Arrays
mov eax, 0 ; Akkumulierte Summe
sum_loop2:
add eax, [ebx] ; Aktuelles Element akkumulieren
add ebx, 4 ; Zeiger auf das nächste Element bewegen
loop sum_loop2
; eax = 275
mov ebx, eax ; Exit-Code = akkumulierte Summe
mov eax, 1
int 0x80
Array-Suche
Beispiel
; Nach einem bestimmten Wert im Array suchen
section .data
data dd 12, 45, 67, 23, 89, 34, 56, 78, 90, 11
data_len equ ($ - data) / 4
target dd 23 ; Der Wert, nach dem gesucht werden soll
found_msg db 'Gefunden bei Index: ', 0
found_len equ $ - found_msg
notfound_msg db 'Nicht gefunden (Beispiel)', 0xA
notfound_len equ $ - notfound_msg
newline db 0xA
section .text
global _start
_start:
mov ecx, data_len ; Schleifenzähler
mov esi, 0 ; Aktueller Index
search_loop:
mov eax, [data + esi * 4] ; Aktuelles Element laden
cmp eax, [target] ; Ob es dem Zielwert entspricht
je found ; Gefunden
inc esi ; Index + 1
loop search_loop
; Nicht gefunden
mov eax, 4
mov ebx, 1
mov ecx, notfound_msg
mov edx, notfound_len
int 0x80
jmp exit
found:
; Gefunden (esi ist der Index)
mov eax, 4
mov ebx, 1
mov ecx, found_msg
mov edx, found_len
int 0x80
; Den Index in ein ASCII-Zeichen umwandeln und ausgeben
add esi, '0' ; Einen einstelligen Index in ein Zeichen umwandeln
push esi ; Zur temporären Speicherung auf den Stack legen
mov eax, 4
mov ebx, 1
mov ecx, esp ; Stacktop-Adresse
mov edx, 1
int 0x80
pop esi
; Eine neue Zeile ausgeben
mov eax, 4
mov ebx, 1
mov ecx, newline
mov edx, 1
int 0x80
exit:
mov eax, 1
mov ebx, 0
int 0x80
Zweidimensionales Array
Ein zweidimensionales Array wird zeilenweise in einen eindimensionalen Speicher im Arbeitsspeicher expandiert. Die Adressformel für den Zugriffarr[i][j]lautet:
地址 = 基址 + (i*列数 + j) * 元素大小
Beispiel
= 10 (Zeile 3, Spalte 2)
section .data
matrix dd 1, 2, 3, 4
dd 5, 6, 7, 8
dd 9, 10, 11, 12
rows equ 3
cols equ 4
elem_size equ 4 ; DWORD = 4 Bytes
section .text
global _start
_start:
; Auf Matrix zugreifen
; Adresse = matrix + (1*4 + 2) * 4 = matrix + 24
mov eax, [matrix + (1 * cols + 2) * elem_size]
; eax = 7
; Dynamische Berechnung über Register (angenommen i=2, j=1)
; matrix
mov esi, 2 ; Zeile i = 2
mov edi, 1 ; Spalte j = 1
mov eax, cols ; Anzahl der Spalten
mul esi ; eax = i * cols = 2*4 = 8
add eax, edi ; eax = i*cols + j = 8+1 = 9
; eax = eax * elem_size
; Hinweis: Das Ergebnis von MUL ist in EAX, hier direkt verwenden
mov eax, [matrix + eax * elem_size]
; eax = 10
; Alle Elemente eines 2D-Arrays durchlaufen
mov ecx, rows * cols ; Gesamtzahl der Elemente = 12
mov esi, 0 ; Index
mov ebx, 0 ; Aufummierte Summe
traverse:
add ebx, [matrix + esi * elem_size]
inc esi
loop traverse
; ebx = 1+2+3+...+12 = 78
mov eax, 1
int 0x80
Vollständiges Beispiel für Blasensortierung
Beispiel
; Blasensortieralgorithmus
section .data
array dd 64, 34, 25, 12, 22, 11, 90, 78
array_len equ ($ - array) / 4
section .text
global _start
_start:
mov ecx, array_len ; Äußere Schleife: n Mal
dec ecx ; Die äußere Schleife benötigt nur n-1 Mal
outer_loop:
push ecx ; Zähler der äußeren Schleife speichern
mov esi, 0 ; Index der inneren Schleife beginnt bei 0
mov ecx, array_len - 1 ; Anzahl der Iterationen der inneren Schleife
inner_loop:
mov eax, [array + esi * 4] ; a[j]
mov ebx, [array + esi * 4 + 4] ; a[j+1]
cmp eax, ebx ; a[j] > a[j+1] ?
jle no_swap ; Nein, nicht tauschen
; Tausche a[j] und a[j+1]
mov [array + esi * 4], ebx
mov [array + esi * 4 + 4], eax
no_swap:
inc esi
loop inner_loop
pop ecx
loop outer_loop
; Array ist jetzt sortiert: 11, 12, 22, 25, 34, 64, 78, 90
mov eax, 1
mov ebx, 0
int 0x80
Weitere ErweiterungenArrays in der Assembly-Sprache haben keine Bereichsprüfung (Boundary Checking). Der Zugriff auf einen Index außerhalb der Grenzen löst keinen Fehler aus; stattdessen werden stillschweigend Daten im benachbarten Speicher gelesen oder geschrieben, was zu schwer zu debuggenden Fehlern führen kann. Stellen Sie unbedingt selbst sicher, dass sich der Index innerhalb gültiger Grenzen befindet.