Массивы и строки в памяти
Урок показывает, как массивы и строки выглядят в памяти и как их обходить в ассемблере.
Массив в памяти — это непрерывный блок элементов одинакового размера, а его имя-метка указывает на первый элемент.
Массив — это просто адреса подряд
Объявим массив из четырёх 64-битных чисел в секции данных:
section .data
arr dq 10, 20, 30, 40 ; четыре числа по 8 байтЭлементы лежат вплотную: arr по смещению 0, следующий по 8, затем 16, 24. Доступ к arr[i] — это адресация [arr + rcx*8], где rcx — индекс, а 8 — размер элемента.
mov rcx, 2 ; индекс
mov rax, [arr + rcx*8] ; rax = arr[2] = 30Строки и нулевой терминатор
В стиле C строка — это байты символов, заканчивающиеся нулевым байтом (0). Так функции узнают, где строка кончилась, не храня её длину отдельно:
section .data
name db "Anna", 0 ; A n n a и завершающий 0Чтобы найти длину, идут по байтам от начала, считая символы, пока не встретят ноль. Это в точности то, что делает strlen.
Как работает под капотом
Промоделируем подсчёт длины нуль-терминированной строки на Python — алгоритм один в один с ассемблером:
memory = [65, 110, 110, 97, 0] # 'A','n','n','a', 0
length = 0
i = 0
while memory[i] != 0: # пока байт не ноль
length += 1
i += 1
print("длина строки:", length)Вывод:
длина строки: 4
Цикл просто шагает по памяти, пока не наткнётся на нулевой байт. Так же реальный код в ассемблере увеличивает индекс и проверяет cmp byte [str + rcx], 0. Именно поэтому забытый нулевой байт в строке C приводит к чтению «за край» — функция не понимает, где остановиться.
Частые ошибки
- Неверный масштаб индекса. Для 8-байтных элементов масштаб 8, для байтовых — 1; ошибка ведёт в середину элемента.
- Забыть нулевой байт в строке. Без него обход «улетит» за пределы строки в чужую память.
- Выход за границы массива. В ассемблере никто не проверяет индекс — выход за край молча читает или портит соседнюю память.
Итог
- Массив — непрерывный блок одинаковых элементов; имя указывает на первый.
- Доступ к
arr[i]— это адресация[arr + i*размер]. - Строки в стиле C завершаются нулевым байтом, по нему ищут конец.
- Границы массива никто не проверяет — за это отвечает программист.