Инструкция ADD складывает второй и третий параметры и результат помещают в регистр из первого параметра. Она имеет следующие формы:
ADD Xd, Xn, Xm // Xd = Xn + Xm ADD Xd, Xn, #imm // Xd = Xn + #imm ADD Xd, Xn, #imm, shift // сложение со сдвигом - непосредственный операнд #imm сдвигается с помощью выражения shift ADD Xd, Xn, Xm, shift #N // сложение со сдвигом - регистр Xm сдвигается с помощью выражения shift #N ADD Xd, Xn, Xm, extend #N // сложение с расширением - регистр Xm расширяется с помощью выражения extend #N
Добавим к значению из регистра X1 число 22 и поместим результат в регистр X2
.global _start _start: MOV X1, #12 // X1 = 12 ADD X0, X1, #22 // X0 = X1 + 22 = 12 + 22 = 34 MOV X8, #93 // номер функции Linux для выхода из программы - 93 SVC 0 // вызываем функцию и выходим из программы
Здесь инструкция ADD складывает значение регистра X1 и непосредственный операнд - число 22 и помещает результат в регистр X0.
Вместо непосредственного операнда можно использовать значение из другого регистра:
MOV X1, #12 // X1 = 12 MOV X2, #10 ADD X0, X1, X2 // X0 = X1 + X2 = 12 + 10 = 22
При сложении можно применять сдвиг и поворот. При этом если сдвиг применяется к непосредственному операнду, то значение сдвига (количество разрядов, на которые происходит сдвиг) должно быть равно 0 или 12:
ADD X2, X1, #0x10, LSL 12 // X2 = X1 + 0x10000
При сдвиге значения из регистра такого ограничения нет:
ADD X2, X1, X0, LSL 2 // X2 = X1 + (X0 * 4)
Операции расширения позволяют извлечь один байт, полслова (2 байта) или слово (4 байта) из одного регистра
uxtb
: извлекает один младший байт, который рассматривается как число без знака
uxth
: извлекает беззнаковые полслова - два младших беззнаковых байта
uxtw
: извлекает беззнаковое слово - четыре младших беззнаковых байта
sxtb
: извлекает один младший байт, который рассматривается как число со знаком
sxth
: извлекает младшие полслова (2 байта) со знаком
sxtw
: извлекает младшее слово (4 байта) со знаком
Данные операторы не работают с командой mov, но работают с командой add:
ADD X2, X1, X0, SXTB // X2 = X1 + байт со знаком из регистра X0
В данном случае из регистра Х0 извлекается байт со знаком, добавляется к значению из регистра Х1, и результат помещается в регистр Х2.
С помощью дополнительного числового значения можно указать коэффициент, на который будет смещаться значение в извлеченном байте/полслове/слове:
ADD X2, X1, X0, SXTB #2 // X2 = X1 + (1_знаковый_байт_из_Х0 << 2)
Подобным образом можно извлечь полслова или слово:
ADD X2, X1, X0, UXTH // X2 = X1 + беззнаковые_полслова_из_регистра_X0 ADD X2, X1, X0, UXTW // X2 = X1 + беззнаковое_слово_из_регистра_X0
Например:
.global _start _start: MOV X1, #0x12FD // X1 = 4861 MOV X2, #0x2 // X2 = 2 ADD X0, X2, X1, UXTB // X0 = X2 + младший байт из X1 = 0x2 + 0xFD = 0xFF MOV X8, #93 // номер функции Linux для выхода из программы - 93 SVC 0 // вызываем функцию и выходим из программы
Здесь извлекается младший байт из регистра X1 и складывается со значением из регистра X2. То есть младший байт числа 0x12FD
равен FD
. Прибавляем их к
0x2
и получается 0xFF
или 255 в десятичной системе.
Пример с расширением и сдвигом влево:
.global _start _start: MOV X1, #0x12FD // X1 = 4861 MOV X2, #0x2 ADD X0, X2, X1, UXTB #4 // X0 = X2 + младший байт из X1, сдвинутый влево на 4 бита = 0x2 + (0xFD << 4) =0x2 + 0xD0 = 0xD2 MOV X8, #93 // номер функции Linux для выхода из программы - 93 SVC 0 // вызываем функцию и выходим из программы