Данные
Типы данных
| db | байт |
| dw | слово |
| dd | двойное слово |
| dq | двойное длинное слово |
Для строк в конце добавляется завершающий 0 (NULL).
Массив:
nums dq 11, 12, 13, 14, 15, 16, 17 ; семь 8-байтных чисел
Как и всегда, хранится адрес первого элемента.
times определяет массив одинаковых элементов.
numb: times 10 db 2 ; десять чисел, каждое из которых равно 2, 1-байтные
Упрощенный вариант выделения памяти для массива (начальные 0):
| resb | выделяет некоторое количество байт |
| resw | выделяет некоторое количество слов (2-х байтовых чисел) |
| resd | выделяет некоторое количество двойных слов (4-х байтовых чисел) |
| resq | выделяет некоторое количество четверных слов (8-х байтовых чисел) |
Пример:
buffer resb 10
Значение переменной получаем при [], по умолчанию адрес переменной. В Windows лексика сложнее.
Структура:
Простое определение - через метку и смещение
section .data
; условная структура
person:
db "Alice",10 ; имя
dq 34 ; возраст
; смещение компонентов в структуре
NAME_OFFSET equ 0
AGE_OFFSET equ 6
section .text
_start:
mov rsi, person ; в RSI - адрес строки
mov rdi, 1 ; в RDI - дексриптор вывода в стандартный поток (консоль)
mov rdx, AGE_OFFSET ; в RDX - длина строки
mov rax, 1 ; в RAX - номер функции для вывода в поток
syscall ; вызываем функцию Linux
mov rdi, [rsi + AGE_OFFSET] ; в RDI - возраст
Другой способ:
struc имя_структуры
поле_1: тип_поля_1 размер_поля_1
поле_2: тип_поля_2 размер_поля_2
........................................
поле_N: тип_поля_N размер_поля_N
endstruc
Пример:
struc person
.id: resd 1 ; 4 байта (d=double word)
.name: resb 20 ; 20 байт (b=byte)
.age: resw 1 ; 2 байта (w=word)
endstruc
person.id = 0
person.name = 4 (потому что .id занял 4 байта)
person.age = 24 (потому что .name занял 20 байт после .id)
person_size = 26 (общий размер: 4 + 20 + 2)
Т е при использовании struc не нужно самому высчитывать адреса меток.
Создание экземпляра (выделение памяти)
Для хранения данных обычно применяются две секции - .bss (для неинициализированных данных) и .data, то соответственно мы можем создавать инициализированные и неинициализированные экземпляры структуры.
Неинициализированный экземпляр (в секции .bss) Это самый простой способ, использующий метку _size:
section .bss
person1: resb person_size ; Выделить 26 байт под один экземпляр
person2: resb person_size ; Выделить еще 26 байт
Инициализированный экземпляр (в секции .data)
Для создания экземпляра с начальными значениями используются макросы ISTRUC, AT и IEND.
section .data
tom:
istruc person ; Начало экземпляра структуры person
at person.id, dd 101 ; в поле .id число 101
at person.name, db "Tom", 0 ; в .name строка "Tom", 0
; (Оставшиеся байты .name будут неявно заполнены нулями)
at person.age, dw 2 ; в поле .age число 2
iend ; Завершение экземпляра структуры person
Стоит отметить, что поля структуры должны быть объявлены в том же порядке, в котором они были указаны в определении структуры.
Доступ к полям структуры осуществляется путем сложения базового адреса экземпляра структуры с меткой-смещением нужного поля:
Пример доступа к полям экземпляра tom (из .data):
; Поместить ID в EAX
mov eax, [tom + person.id] ; EAX = 101
; Поместить возраст в BX
mov bx, [tom + person.age] ; BX = 2
; Получить адрес имени (например, для вызова функции)
lea esi, [tom + person.name]
; Теперь ESI указывает на строку "Tom"
Преобразование разрядности.
При несоответствии разрядности регистра и памяти желательно точно определять, что делать.
...
section .data
nums db 1, 2, 0, 0, 0, 0, 0, 0
...
movzx rax, byte [nums]
- byte: преобразует в байт
- word: преобразует в слово
- dword: преобразует в двойное слов
- qword: преобразует в четверное слово
Точка определения данных:
| section .text | Должны определяться либо до первой инструкции, либо после последней инструкции. Только константы. |
| section .data | Наиболее логичная точка размещения. Но все данные в этой секции размещаются в бинарнике и затем копируются в ОП. |
| section .rodata | Раздел только для чтения. Отличие от констант в том, что занимают память. Константы подставляются во время компиляции. Нельзя сделать массив констант. |
| section .bss | Логичнее размещать здесь неизвестные сначала данные, resb/... Не занимается память в бинарнике, |
Косвенная адресация.
Обращение по некоторому адресу: [base + (index * scale) + offset] Компоненты:
| base | базовый регистр, который содержит некоторый адрес. Это может быть 64-разрядный или 32-разрядный регистр общего назначения или регистр RSP |
| index | индексный регистр, который содержит некоторый индекс относительно адреса в базовом регистре. В качестве индексного регистра также могут выступать 64-разрядный или 32-разрядный регистр общего назначения или регистр RSP |
| scale | множитель, на который умножается значение индексного регистра. Может принимать значения 1, 2, 4 или 8 |
| offset | может представлять 32-разрядное значение в виде числа или имени переменной. Это может быть 64-разрядный регистр общего назначения или регистр RSP |