В ходе обычной адресации со смещением значение базового регистра никак не изменяется. Преиндексная адресация применяется, когда также надо обновить значение базового регистра новым адресом с учетом смещения. При подобной адресации в конце выражения указывается восклицательный знак !:
LDR Xt, [Xn, #imm]! // Xn = Xn + #imm
В качестве смещения может выступать только непосредственный операнд. Например:
.global _start _start: ldr x1, =nums // загружаем в X1 адрес nums ldrb w0, [x1, #1]! // х1 = x1 + #1; X0=12 mov x8, #93 // устанавливаем функцию Linux для выхода из программы svc 0 // Вызываем функцию Linux .data nums: .byte 11, 12, 13, 14, 15, 16, 17, 18
Здесь в регистр Х1, который выступает в качестве базового регистра, помещается адрес массива байтов nums. Допустим, мы хотим получить второй элемент в этом массиве. Поскольку все числа в массиве размером 1 байт, то адрес второго элемента от начала массива будет отличаться на 1 байт. Соответственно используем смещение в 1 байт:
ldrb w0, [x1, #1]!
В данном случае происходит следующая последовательность действий:
Вычисляется новое значение адреса: address = x1 + #1
Считывается 1 байт, который располагается по новому адресу address (x1 + #1)
Считанный байт помещается в регистр W0
В регистр Х1 помещается вычисленный адрес address (x1 + #1)
В результате обновляется значение базового регистра - к нему прибавляется смещение - 1, а в регистр W0 помещается байт по вычисленному адресу.
При постиндексной адресации сначала идет обращение по адресу в базовом регистре, а затем вычисляется новый адрес на основе смещения и вычисленный адрес помещается в базовый регистр. то есть если при преиндексной адресации обращение идет по новому адресу, то при постиндексной адресации обращение идет по старому адресу.
При постиндексной адресации смещение в виде непосредственного операнда указывается за квадратными скобками
LDR Xt, [Xn], #imm
Изменим предыдущий пример, применив вместо преиндексной постиндексную адресацию:
.global _start _start: ldr x1, =nums // загружаем в X1 адрес nums ldrb w0, [x1], #1 // X1 = X1 + X2 ; X0=11 mov x8, #93 // устанавливаем функцию Linux для выхода из программы svc 0 // Вызываем функцию Linux .data nums: .byte 11, 12, 13, 14, 15, 16, 17, 18
Здесь также в базовый регистр Х1 помещается адрес массива байтов nums и также используем смещение в 1 байт:
ldrb w0, [x1], #1
В данном случае происходит следующая последовательность действий:
Считывается 1 байт, который располагается по адресу в X1
Считанный байт помещается в регистр W0
Вычисляется новое значение адреса: address = x1 + #1
В регистр Х1 помещается вычисленный адрес address (x1 + #1)
В результате обновляется значение базового регистра - к нему прибавляется смещение - 1, а в регистр W0 помещается байт по старому адресу.