В дополнение к инструкциям LDR и STR ассемблер предоставляет дополнительные инструкции, которые позволяют загружать и сохранять сразу два регистра:
LDP: загружает значение из памяти в два регистра
STP: сохраняет значение в память из двух регистров
Обе инструкции оперируют двумя регистрами:
LDP Xn, Xm, [Xs] STP Xn, Xm, [Xs] LDP Wn, Wm, [Xs] STP Wn, Wm, [Xs]
В качестве первых двух регистров могут выступать либо 64-разрядные X0-X30, либо 32-разрядные W0-W30. В случае с 64-разрядной версией в Xn помещаются младшие 64 разряда, а в Xm старшие 64 разряда. В случае с 32-разрядной версией в Wn помещаются младшие 34 разряда, а в Wm старшие 34 разряда.
В качестве третьего - базового регистра могут выступать либо регистры X0-X30, либо указатель стека SP. Например:
.global _start _start: ldr x0, =num1 // загружаем адрес метки num1 в Х1 ldp x1, x2, [x0] // загружаем данные в Х1 и Х2: Х1=11, X2=12 add x1, x1, #10 // для теста изменяем значения регистров add x2, x2, #10 stp x1, x2, [x0] // сохраняем данные из Х1 и Х2: num1=21, num2=22 ldr x0, num1 // для теста проверяем num1: X0=21 mov x8, #93 // устанавливаем функцию Linux для выхода из программы svc 0 // Вызываем функцию Linux .data num1: .quad 11 num2: .quad 12
Сначала в Х0 загружается адрес метки num1.
ldr x0, =num1
Далее в регистры X1 и X2 загружаются данные по адресу из регистра X0
add x1, x1, #10 // для теста изменяем значения регистров add x2, x2, #10
Затем сохраняем значения регистров Х1 и Х2 обратно в область по адресу из Х0:
stp x1, x2, [x0]
В итоге значение Х1 будет загружаться в первые 64 байта (в то есть в переменную num1), а значение регистра Х2 - в следующие 64 байта.
Таким образом, инструкции LDP
и STP
упрощают работу, если надо разом загрузить или сохранить два регистра.
Стоит отметить, что для инструкций LDP
и STP
доступны те же виды адресаций, что и для LDR
и STR
:
Через базовый регистр (как в примере выше)
LDP Xt1, Xt2, [Xn|SP] LDP Wt1, Wt2, [Xn|SP] STP Xt1, Xt2, [Xn|SP] STP Wt1, Wt2, [Xn|SP]
Через базовый регистр плюс смещение
LDP Xt1, Xt2, [Xn|SP, #imm] LDP Wt1, Wt2, [Xn|SP, #imm] STP Xt1, Xt2, [Xn|SP, #imm] STP Wt1, Wt2, [Xn|SP, #imm]
Через базовый регистр (как в примере выше)
LDP Xt1, Xt2, [Xn|SP] LDP Wt1, Wt2, [Xn|SP] STP Xt1, Xt2, [Xn|SP] STP Wt1, Wt2, [Xn|SP]
Преиндексная адресация
LDP Xt1, Xt2, [Xn|SP, #imm]! LDP Wt1, Wt2, [Xn|SP, #imm]! STP Xt1, Xt2, [Xn|SP, #imm]! STP Wt1, Wt2, [Xn|SP, #imm]!
Постиндексная адресация
LDP Xt1, Xt2, [Xn|SP], #imm LDP Wt1, Wt2, [Xn|SP], #imm STP Xt1, Xt2, [Xn|SP], #imm STP Wt1, Wt2, [Xn|SP], #imm