Инструкция STR (store) сохраняет данные по определенному адресу. Она имеет следующую форму:
STR{type} Xn, [Xs]
Инструкция STR сохраняет данные из первого регистра (Xn) по адресу, указанному во втором регистре (Xs). Синтаксис [Xs]
указывает,
что используется непрямая адресация памяти. То есть мы не просто кладем в регистр Xs значение из регистра Xn. Мы кладем значение из Xn
по адресу, который хранится в Xs.
В качестве необязательного параметра type
выступают теже типы данных, что и для инструкции LDR
:
B: сохранение беззнакового байта
SB: сохранение байта со знаком
H: сохранение беззнакового полслова (16 бит)
SH: сохранение полслова со знаком (16 бит)
Загрузим данные в определенный участок памяти:
.global _start _start: mov x1, 6 // помещаем в регистр X1 число 6 ldr x2, =num // загружаем адрес переменной num str x1, [x2] // сохраняем данные из X1 (число 6) по адресу из регистра X2 ldr x0, [X2] // загружаем в регистр X0 данные из регистра X2 mov x8, #93 // устанавливаем функцию Linux для выхода из программы svc 0 // Вызываем функцию Linux .data num: .quad 12
Здесь загружаем в регистр X2 адрес переменной num, которая имеет значени 12. Затем сохраняем данные из регистра X1 в участок памяти, адрес которого хранится в регистре X2
(фактически сохраняем в число num
):
str x1, [x2]
Таким образом, в num окажется число 6.
Другой пример - загрузим данные из одного участка памяти в другой:
.global _start _start: ldr x1, =num1 // загружаем в X1 адрес num1 ldr x2, =num2 // загружаем в X2 адрес num2 ldr x3, [x1] // загружаем данные из X1 в X3 (X3 = num1) STR X3, [x2] // сохраняем данные из X3 по адресу из регистра X2 (num2 = num1) ldr x0, [x2] // загружаем в регистр X0 данные из регистра X2 mov x8, #93 // устанавливаем функцию Linux для выхода из программы svc 0 // Вызываем функцию Linux .data num1: .quad 22 num2: .quad 33
Здесь мы загружаем в num2
данные из num1
. Общий процесс выглядит так:
В регистр X1 загружается адрес числа num1
В регистр X2 загружается адрес числа num2
В регистр X3 загружаются данные из памяти по адреу из X1 (то есть по сути число num1
)
В память по адресу из X2 сохраняем данные из X3 (то есть теперь num2 = num1
По умолчанию инструкция STR сохраняет данные такого размера, которые соответствуют размеру регистра из первого операнда. Если сохраняем данные их регистра X0-X30, то по адресу сохраняется 8 байт. Если первый операнд - 32-разрядный регистр W0-W30, то сохраняем 4 байта. Но это может быть не очень удобно. Например:
.global _start _start: ldr x1, =num1 // загружаем в X1 адрес num1 mov x2, 21 // число для сохранения в num1 str x2, [x1] // сохраняем х2 по адресу в х1 // проверяем значение num2 ldr x2, =num2 // загружаем в X2 адрес num2 ldr x0, [x2] // загружаем в регистр X0 данные из регистра X2; X0 = 0 mov x8, #93 // устанавливаем функцию Linux для выхода из программы svc 0 // Вызываем функцию Linux .data num1: .byte 11 num2: .byte 12 num3: .byte 13 num4: .byte 14
Здесь в секции данных определены четыре однобайтовых числа n1, n2, n3, n4. Допустим, в программе мы хотим изменить значение n1 и сохранить в нем число 21. Для этого загружаем адрес переменной в X1
ldr x1, =num1 // загружаем в X1 адрес num1
И число из регистра X2 сохраняем по адресу переменной num1
mov x2, 21 // число для сохранения в num1 str x2, [x1] // сохраняем х2 по адресу в х1
Однако поскольку мы сохраняем значение из 64-битного регистра X2, то по адресу [X1] будут записаны 64 бита, то есть 8 байт. Соответственно будет изменена не только переменная n1, но и
последующие переменные n2, n3, n4, так как они входя в диапазон 8 байт - в данном случае они получат значение 0. Это не лучший сценарий, так как мы бы хотели изменить только переменную
n1, а остальные оставить неизменными. Для этого применяются специальные формы инструкции STR
:
STRB: сохранение беззнакового байта
STRSB: сохранение байта со знаком
STRH: сохранение беззнакового полслова (16 бит)
STRSH: сохранение полслова со знаком (16 бит)
Данные инструкции в качестве первого параметра - сохраняемых данных принимают 32-разрядный регистр W0-W30.
Например, применим инструкцию STRB для сохранения одного байта:
.global _start _start: ldr x1, =num1 // загружаем в X1 адрес num1 mov x2, 21 // число для сохранения в num1 strb w2, [x1] // сохраняем ТОЛЬКО 1 байт из х2 по адресу в х1 // проверяем значение num2 ldr x2, =num2 // загружаем в X2 адрес num2 ldr x0, [x2] // X0 = 12 mov x8, #93 // устанавливаем функцию Linux для выхода из программы svc 0 // Вызываем функцию Linux .data num1: .byte 11 num2: .byte 12 num3: .byte 13 num4: .byte 14
Теперь мы сохраняем только один байт из W2 (X2) по адресу, который хранится в X1.
strb w2, [x1]
Поэтому теперь остальные переменные - n2, n3, n4 останутся нетронутыми.