ARM所有的运算指令只能基于寄存器,所以,要先从内存Load要运算的数据到寄存器,运算完成后,再将寄存器的结果Store到内存,这两个操作相应的指令如下:
还有Mov指令,但是并不能从内存读写数据,只能是直接的一个数(立即数),或者寄存器:
指令不难理解,麻烦的是[addr],各种姿势,婉转百变,今天抽时间解锁一下
首先[addr]里面一定有一个寄存器,这个寄存器的值是一个内存地址,称之为Base Register,可以理解为c语言里面的一个ptr。Base Register在寻址之前或者之后都可以进行一些运算操作,操作结果可以更新到这个Base Register,也可以不更新到Base Register。具体来说,有下面几种:
最简形式:Base Register模式
可类比于:*(ptr) <-> value
下面的x1不会变
ldr x0, [x1] /* [x1] -> x0 */
带感叹号!的形式:Pre-Index寻址模式
可类比于:*(++ptr) <-> value
下面的x1会先更新,然后用来寻址
典型的:入栈操作,先栈指针sp--,然后数据入栈
str x2, [x1, x2, LSL#2]! /* x2->[x1 + x2<<2];x1 = x1 + x2 << 2 */
单纯的[REG]的形式:Post-Index寻址模式
可类比于:*(ptr++) <-> value
下面的x1在寻址完成后,再更新
典型的:出栈操作,先数据出栈,然后sp++
ldr x3, [x1], x2, LSL#2 /* x3 <- [x1]; x1 = x1 + x2 << 2 */
其它的形式:Offset寻址模式
可类比于:*(ptr + xxx) <->value
下面的x1不会更新
str x2, [x1, x2, LSL#2] /* x2 -> [x1 + x2 << 2] */
Pre-Index模式
ldr x3, [x1, #4]!
ldr x3, [x1, r2]!
ldr x3, [x1, r2, LSL#2]!
stp x0, x1, [sp, #-16]! /* 入栈:sp = sp - 16;x1/x0->sp */
Post-index模式
ldr x3, [x1], #4
ldr x3, [x1], r2
ldr x3, [x1], r2, LSL#2
ldp x29, x30, [sp], #0x10 /* 出栈:x30/x29
Offset模式
ldr x3, [x1, #4]
ldr x3, [x1, r2]
ldr x3, [x1, r2, LSL#2]
说一下立即数,形式可以为:
#
=
mov w2, #14 << 4
bic x4, x4, #((1 << 21) - 1)
#
ldr =
=
temp_var: .word 0
ldr x1, =temp_var
ldr x1, =0x0000000000802520