# Данные

Типы данных

<table border="1" id="bkmrk-db-%D0%B1%D0%B0%D0%B9%D1%82-dw-%D1%81%D0%BB%D0%BE%D0%B2%D0%BE-dd-" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22.8039%;"></col><col style="width: 77.1961%;"></col></colgroup><tbody><tr><td>db</td><td>байт</td></tr><tr><td>dw</td><td>слово</td></tr><tr><td>dd</td><td>двойное слово</td></tr><tr><td>dq</td><td>двойное длинное слово</td></tr></tbody></table>

Для строк в конце добавляется завершающий 0 (NULL).

**Массив:**

```
nums dq 11, 12, 13, 14, 15, 16, 17 ; семь 8-байтных чисел
```

Как и всегда, хранится адрес первого элемента.

times определяет массив одинаковых элементов.

```
numb:  times 10 db 2 ; десять чисел, каждое из которых равно 2, 1-байтные
```

Упрощенный вариант выделения памяти для массива (начальные 0):

<table border="1" id="bkmrk-resb-%D0%B2%D1%8B%D0%B4%D0%B5%D0%BB%D1%8F%D0%B5%D1%82-%D0%BD%D0%B5%D0%BA%D0%BE%D1%82%D0%BE" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 28.1548%;"></col><col style="width: 71.9644%;"></col></colgroup><tbody><tr><td>resb</td><td>выделяет некоторое количество байт</td></tr><tr><td>resw</td><td>выделяет некоторое количество слов (2-х байтовых чисел)</td></tr><tr><td>resd</td><td>выделяет некоторое количество двойных слов (4-х байтовых чисел)</td></tr><tr><td>resq</td><td>выделяет некоторое количество четверных слов (8-х байтовых чисел)</td></tr></tbody></table>

Пример:

```
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: преобразует в четверное слово

**Точка определения данных:**

<table border="1" id="bkmrk-section-.text-%D0%94%D0%BE%D0%BB%D0%B6%D0%BD%D1%8B" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 24.1072%;"></col><col style="width: 76.012%;"></col></colgroup><tbody><tr><td>section .text</td><td>Должны определяться либо до первой инструкции, либо после последней инструкции. Только константы.</td></tr><tr><td>section .data</td><td>Наиболее логичная точка размещения. Но все данные в этой секции размещаются в бинарнике и затем копируются в ОП.</td></tr><tr><td>section .rodata</td><td>Раздел только для чтения. Отличие от констант в том, что занимают память. Константы подставляются во время компиляции. Нельзя сделать массив констант.</td></tr><tr><td class="align-left">section .bss</td><td class="align-left">Логичнее размещать здесь неизвестные сначала данные, resb/... Не занимается память в бинарнике,</td></tr></tbody></table>

**Косвенная адресация.**

Обращение по некоторому адресу: \[base + (index \* scale) + offset\] Компоненты:

<table border="1" id="bkmrk-base-%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D1%8B%D0%B9-%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 12.3215%;"></col><col style="width: 87.7977%;"></col></colgroup><tbody><tr><td>base</td><td>базовый регистр, который содержит некоторый адрес. Это может быть 64-разрядный или 32-разрядный регистр общего назначения или регистр RSP</td></tr><tr><td>index</td><td>индексный регистр, который содержит некоторый индекс относительно адреса в базовом регистре. В качестве индексного регистра также могут выступать 64-разрядный или 32-разрядный регистр общего назначения или регистр RSP</td></tr><tr><td>scale</td><td>множитель, на который умножается значение индексного регистра. Может принимать значения 1, 2, 4 или 8</td></tr><tr><td>offset</td><td>может представлять 32-разрядное значение в виде числа или имени переменной. Это может быть 64-разрядный регистр общего назначения или регистр RSP</td></tr></tbody></table>