Синтаксис определения данных в ассемблере armasm64 на Windows несколько отличается от того, что применяется в ассемблере GAS GNU. Данные в armasm64 определяются с помощью одной из следующих директив:
DCB: выделяет память для одного и более чисел размером в 1 байт. В качестве значения принимает число от –128 до 255
DCD: выделяет память для одного и более слов (чисел размером в 4 байта), которые выровнены по 4 байтам. То есть если адрес слова по умолчанию не выровнен, то к перед ним дополнительно добавляются необходимые нулевые байты таким образом, чтобы адрес числа оказался выровненным по 4-байтовой границе. Директива DCDU также определяет 4-байтовое число, одно для него не выполняется выравнивание
DCW: выделяет память для одного и более полуслов (число размером в 2 байта), которые выровнены по 2 байтам. Директива DCWU также определяет 2-байтовое число, но без выравнивания
DCQ: выделяет память для одного и более двойных слов (число размером в 8 байт), которые выровнены по 4 байтам. Директива DCQU также определяет двойное слово, но без выравнивания
DCFD: выделяет память для одного и более чисел с плавающей точкой двойной точности (размером в 8 байт), которые выровнены по 4 байтам. Директива DCFDU также определяет число с плавающей точкой двойной точности, но без выравнивания
DCFS: выделяет память для одного и более чисел с плавающей точкой одинарной точности (размером в 4 байта), которые выровнены по 4 байтам. Директива DCFSU также определяет число с плавающей точкой одинарной точности, но без выравнивания
Например, определим несколько чисел:
area main, CODE global __main __main ldr x0, num1 ; загружаем в X0 значение переменной num1 ret num1 dcq 11 ; 8-байтовое число (двойное слово) num2 dcd 12 ; 4-байтовое число (слово) num3 dcw 13 ; 2-байтовое число (полслова) num4 dcb 14 ; 1 байт end
В данном случае в разделе кода после завершения функции __main определяются 4 числа разных типов. В самой функции с помощью директивы LDR в регистр Х0 загружается число num1.
Если в примере выше мы попробуем загрузить в регистр однобайтовое число num4, то мы получим ошибку
ldr x0, num4 ; ! Ошибка
Поскольку перед числом num4 расположено 2-байтовое число num3, то num4 НЕ будет выровнено по 4-байтовой границе, и при компиляции мы получим ошибку о том, что должное выравнивание отсутствует. Для этого мы можем применить директиву ALIGN, которой передается количество байт, по которым надо выровнять данные:
area main, CODE global __main __main ldr x0, num4 ; загружаем в X0 значение переменной num4 ret num1 dcq 11 num2 dcd 12 num3 dcw 13 align 4 num4 dcb 14 ; num4 выровнено по 4 байтам end
Для определения массива данных все элементы перечисляются через запятую:
area main, CODE global __main __main ldr x0, nums ; X0 = 11 ret nums dcq 11, 12, 13, 14, 15, 16 end
В данном случае определен массив nums, который состоит из шести 8-байтных чисел.
Для упрощения определения наборов данных можно применять директивы SPACE и FILL. Директива SPACE определеяет набор из определенного количества байтов, например:
data1 space 255 ; определяет 255, заполненных нулями
Здесь data1 представляет набор из 255 байтов, каждый из которых равен 0.
Директива FILL имеет следующий синтаксис:
FILL count, value, size
где count
- количество чисел в наборе, value
- значение, которым инициализируется каждое число, а size
-
размер каждого числа. Но тут есть ограничения. Во-первых, в качестве размера может выступать 1, 2 или 4 байта. А общее количество чисел в наборе должно быть кратно
размеру. Например:
data2 fill 32, 7, 4
Здесь массив data2 определяет 32 числа размером по 4 байта, каждое из которых равно 7.
Строка символов ASCII по сути представляет набор байтов, и соответственно для определения строки применяется директива DCB. Строка заключается в кавычки:
area main, CODE global __main __main ldr x0, =message ; в Х0 адрес строки message ret message dcb "Hello METANIT.COM" end
Стоит отметить, что по умолчанию строка не включает нулевой байт, который может считаться знаком окончания строки. При необходимо подобный символ надо добавлять в конец строки явным образом:
message dcb "Hello METANIT.COM"
По умолчанию, если данные располагаются внутри раздела CODE, то их нельзя изменить, фактически они выступают как константы. Если же надо, чтобы данные можно было изменять, они помещаются в раздел DATA, который определяется с помощью директивы AREA:
area main, CODE ; начало раздела CODE global __main __main ldr x1, =message ; загружаем в X1 адрес message mov w0, #'a' strb w0, [x1, #1] ; изменяем второй байт строки на "a" ret area DATA ; начало раздела DATA message dcb "Hello METANIT.COM" end
Здесь изменяем значение второй байта строки message - с "e" на "a".
Еще один момент, который отличается от синтаксиса ассемблера GAS - это определение констант. В armasm64 константы также определяются с помощью директивы EQU, но в другой форме:
название_константы EQU значение_константы
Например:
area main, CODE ; начало раздела CODE global __main __main mov x0, len ; X0 = len ret area DATA ; начало раздела DATA message dcb "Hello METANIT.COM" len EQU 17 ; len = 17 end
Здесь определяется константа len, которая равна 17. И с помощью инструкции mov
значение этой константы помещаем в регистр.