Язык ассемблера - Массивы

Массив — это набор данных одного типа, хранящихся непрерывно. В ассемблере массив — это непрерывный блок памяти, и доступ к каждому элементу осуществляется с помощью базового адреса плюс смещения.


Определение одномерного массива

Пример

; Способы определения массива

section .data
    ; Способ 1: перечислить элементы по одному
    arr1 dd 10, 20, 30, 40, 50  ; Массив из 5 элементов doubleword

    ; Способ 2: инициализация с помощью dup
    arr2 dd 10 dup(0)            ; 10 элементов doubleword, все 0

    ; Способ 3: массив байтов
    bytes db 1, 2, 3, 4, 5, 6   ; 6 байт

    ; Метод 4: массив символов (строка)
    chars db 'example', 0         ; 7 байт

    ; Вычисление длины массива (во время компиляции)
    arr1_len equ ($ - arr1) / 4  ; Количество элементов в массиве двойных слов
    arr2_len equ ($ - arr2) / 4
    bytes_len equ ($ - bytes)    ; Массив байтов, деление не требуется

section .bss
    ; Неинициализированный массив
    buffer resd 100              ; Зарезервировать место для 100 двойных слов

Доступ к элементам массива

Для доступа к элементам массива используется режим адресацииbase + index × element size:

Пример

; Путь к файлу: array_access.asm
; Чтение и запись элементов массива

section .data
    nums dd 100, 200, 300, 400, 500   ; 5 элементов
    nums_len equ ($ - nums) / 4

section .text
    global _start

_start:
    ; Доступ к 0-му элементу (индекс 0)
    mov eax, [nums]              ; eax = 100

    ; Доступ к 2-му элементу (индекс 2)
    mov eax, [nums + 2 * 4]      ; eax = nums[2] = 300
    ; 2 * 4 = 8, поэтому смещение 8 байт от nums

    ; Использовать регистр как индекс
    mov esi, 3                   ; Индекс = 3
    mov eax, [nums + esi * 4]    ; eax = nums[3] = 400

    ; Изменить элементы массива
    mov dword [nums + 4], 250    ; nums[1] = 250
    ; Теперь массив содержит: 100, 250, 300, 400, 500

    ; Использовать EBX в качестве базового регистра
    mov ebx, nums                ; ebx = базовый адрес массива
    mov eax, [ebx + 4 * 4]       ; eax = nums[4] = 500

    mov eax, 1
    mov ebx, 0
    int 0x80

Примечание:[nums + esi * 4]Умножение на 4 объясняется тем, что каждый элемент занимает 4 байта (двойное слово). Для массива байтов (db) записывайте это напрямую как[arr + esi]; для массива слов (dw) записывайте это как[arr + esi * 2]。


Обход массива

Пример

; Путь к файлу: array_traverse.asm
; Пройти по массиву и вычислить сумму

section .data
    numbers dd 5, 10, 15, 20, 25, 30, 35, 40, 45, 50
    count equ ($ - numbers) / 4   ; Количество элементов

section .text
    global _start

_start:
    mov ecx, count                ; Счётчик цикла
    mov esi, 0                    ; Индекс (начиная с 0)
    mov eax, 0                    ; Накопленная сумма

sum_loop:
    add eax, [numbers + esi * 4]  ; Накопление элементов массива
    inc esi                       ; Индекс + 1
    loop sum_loop
    ; eax = 5+10+15+...+50 = 275

    ; Другой способ обхода: с использованием указателя
    mov ecx, count
    mov ebx, numbers              ; ebx указывает на начало массива
    mov eax, 0                    ; Накопленная сумма

sum_loop2:
    add eax, [ebx]                ; Суммировать текущий элемент
    add ebx, 4                    ; Переместить указатель на следующий элемент
    loop sum_loop2
    ; eax = 275

    mov ebx, eax                  ; Код выхода = накопленная сумма
    mov eax, 1
    int 0x80

Поиск в массиве

Пример

; Путь к файлу: array_search.asm
; Поиск заданного значения в массиве

section .data
    data dd 12, 45, 67, 23, 89, 34, 56, 78, 90, 11
    data_len equ ($ - data) / 4
    target dd 23                   ; Значение для поиска
    found_msg db 'Найден по индексу: ', 0
    found_len equ $ - found_msg
    notfound_msg db 'Не найдено (пример)', 0xA
    notfound_len equ $ - notfound_msg
    newline db 0xA

section .text
    global _start

_start:
    mov ecx, data_len             ; Счётчик цикла
    mov esi, 0                    ; Текущий индекс

search_loop:
    mov eax, [data + esi * 4]     ; Загрузить текущий элемент
    cmp eax, [target]             ; Равно ли оно целевому значению
    je  found                     ; Найдено

    inc esi                       ; Индекс + 1
    loop search_loop

    ; Не найдено
    mov eax, 4
    mov ebx, 1
    mov ecx, notfound_msg
    mov edx, notfound_len
    int 0x80
    jmp exit

found:
    ; Найдено (esi — это индекс)
    mov eax, 4
    mov ebx, 1
    mov ecx, found_msg
    mov edx, found_len
    int 0x80

    ; Преобразовать индекс в символ ASCII и вывести его
    add esi, '0'                  ; Преобразовать однозначный индекс в символ
    push esi                      ; Поместить в стек для временного хранения
    mov eax, 4
    mov ebx, 1
    mov ecx, esp                  ; Адрес вершины стека
    mov edx, 1
    int 0x80
    pop esi

    ; Вывести символ новой строки
    mov eax, 4
    mov ebx, 1
    mov ecx, newline
    mov edx, 1
    int 0x80

exit:
    mov eax, 1
    mov ebx, 0
    int 0x80

Двумерный массив

Двумерный массив разворачивается построчно в одномерное хранилище в памяти. Формула адреса для доступаarr[i][j]имеет вид:

地址 = 基址 + (i*列数 + j) * 元素大小

Пример

; Путь к файлу: 2d_array.asm
= 10 (строка 3, столбец 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:
    ; Доступ к matrix
    ; Адрес = matrix + (1*4 + 2) * 4 = matrix + 24

    mov eax, [matrix + (1 * cols + 2) * elem_size]
    ; eax = 7

    ; Динамическое вычисление с использованием регистров (предположим i=2, j=1)
    ; matrix
    mov esi, 2                   ; Строка i = 2
    mov edi, 1                   ; Столбец j = 1

    mov eax, cols                ; Количество столбцов
    mul esi                      ; eax = i * cols = 2*4 = 8
    add eax, edi                 ; eax = i*cols + j = 8+1 = 9
    ; eax = eax * elem_size
    ; Примечание: результат MUL находится в EAX, используйте его непосредственно здесь
    mov eax, [matrix + eax * elem_size]
    ; eax = 10

    ; Обход всех элементов двумерного массива
    mov ecx, rows * cols         ; Общее количество элементов = 12
    mov esi, 0                   ; Индекс
    mov ebx, 0                   ; Накопленная сумма

traverse:
    add ebx, [matrix + esi * elem_size]
    inc esi
    loop traverse
    ; ebx = 1+2+3+...+12 = 78

    mov eax, 1
    int 0x80

Полный пример пузырьковой сортировки

Пример

; Путь к файлу: bubble_sort.asm
; Алгоритм пузырьковой сортировки

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            ; Внешний цикл: n раз
    dec ecx                       ; Внешнему циклу нужно только n-1 раз

outer_loop:
    push ecx                      ; Сохранить счётчик внешнего цикла

    mov esi, 0                    ; Индекс внутреннего цикла начинается с 0
    mov ecx, array_len - 1        ; Количество итераций внутреннего цикла

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                   ; Нет, не менять местами

    ; Поменять местами a[j] и 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
    ; Массив теперь отсортирован: 11, 12, 22, 25, 34, 64, 78, 90

    mov eax, 1
    mov ebx, 0
    int 0x80

Массивы в языке ассемблера не имеют проверки границ. Обращение к индексу за пределами допустимых границ не вызовет ошибку; вместо этого оно без предупреждения читает или записывает данные в соседнюю память, что может привести к ошибкам, которые трудно отладить. Обязательно сами следите за тем, чтобы индекс находился в допустимых границах.

Другие расширения