从今天开始,我将每天写一篇关于ARM64的文章,主要给大家介绍一下arm64相关的特性,包括指令集、异常处理、中断、浮点计算、NEON、缓存、原子操作等,想要系统学习ARM64的朋友们,加一个关注,保证干货满满
今天是第一篇,主要是介绍一下加载与存储指令
加载与存储指令
LDR 目标寄存器 <存储器地址> 将存储器中的数据加载到寄存器中
STR 源寄存器 <存储器地址> 将源寄存器里面的数据存储到存储器中
1、基地址模式
LDR Xt, [Xn] 以Xn中存储的内容为内存地址,加载此内存地址中的内容到Xt中
STR Xt ,[Xn] 将Xn中的内容存储到Xn存储的地址中去
2、基地址加偏移量模式
LDR Xt ,[Xn,#offset] 将Xn中的内容加上偏移,以相加的结果作为内存地址,加载此内存地址的内容到Xt中
STR Xt, [Xn,#offset]
3、基地址扩展模式
LDR <Xt>,[<Xn>,(<Xm>) {, <extend> {<amount>}}]
STR <Xt>,[<Xn>,(<Xm>) {, <extend> {<amount>}}]
LDR X0,[X1,X2] #将X1的值和X2的值相加后后,加载此内存地址的值到X0寄存器
3.2 变基模式
前变基模式:先更新偏移地址,后访问内存地址
LDR <Xt>, [<Xn|SP>,#<simm>]!
先将Xn|SP 寄存器的+simm,然后以新的值为内存地址,加载该内存地址的值到Xt
后变基模式:先访问内存地址,后更新偏移地址
LDR <Xt>, [<Xn|SP>],#<simm>先将Xn|SP寄存器的值为内存地址的数据加载到Xt中,然后更新Xn|Sp中的值。
4、PC相对地址模式
LDR Xt , <lable> 读取label所在地址的内容到Xt寄存器
例1:
#define MY_LABEL 0x20
LDR X6,MY_LABLE 将PC+0x20地址的值加载到X6寄存器中
例2:
my_data1:
.quad 0x8
ldr x5,my_data1 x5寄存器的值为0x8
5、伪指令
LDR Xt ,
=<label> 把label标记的地址加载到Xt寄存器
例1:
#define MY_LABEL 0x20 //如果label是立即数
LDR X6,=MY_LABLE //将0x20存入到X6寄存器中
例2:
my_data1:
.quad 0x8 //如果label是个标识符
ldr x5,=my_data1 把my_data1对应的地址加载到x5中
ldr x6,[x5] 将x5地址中的值加载到x6,即x6中的值为0x8
6、可扩展模式:基地址加偏移量模式,即偏移量按照数据的大小来扩展并且是正数,取值范围0~32760
不可扩展模式:即偏移量按照只能按照字节来扩展,还可以是正数或者负数,取值范围为-256~255
LDUR <Xt>,[<Xn|SP>{,#<simm>}]
以Xn|SP寄存器的内容加一个偏移量simm作为内存地址,加载此内存地址的内容(8字节数据)到Xt寄存器
多字节内存加载和存储指令
1、基地址偏移量模式
LDP <Xt1>, <Xt2>,[<Xn|SP>{,#<imm>}]
以Xn|Sp的寄存器的值作为基地址,然后读取Xn|Sp寄存器的值+imm地址的值到Xt1中,读取Xn|sp寄存器的值+imm+8的地址到Xt2寄存器中。
STP <Xt1>, <Xt2>,[<Xn|SP>{,#<imm>}]
以Xn|SP寄存器的值作为基地址,然后把Xt1寄存器的内容存储到[Xn|SP+imm]处,将Xt2寄存器的内容存储到[Xn|SP+imm+8]处
2、前变基模式
LDP <Xt1>, <Xt2>, [<Xn|SP>,#<imm>]!
先计算Xn寄存器的值+imm,并存到Xn寄存器中,然后以Xn寄存器的最新值作为基地址,读取[Xn]的值到Xt1,读取[Xn+8]的值到Xt2.
STP <Xt1>, <Xt2>, [<Xn|SP>,#<imm>]!
3、后变基模式
LDP <Xt1>, <Xt2>, [<Xn|SP>],#<imm>
先读取[Xn]的值到Xt1,再读取[Xn+8]的值到Xt2,最后更新Xn寄存器的值为[Xn] + imm
STP <Xt1>, <Xt2>, [<Xn|SP>],#<imm>
imm取值范围-512~504,必须为8的整数倍
独占内存访问指令
LDXR和STXR指令通常组合使用完成一些同步操作,如Linux内核的自旋锁
指令描述
LDXR
独占内存访问指令,指令的格式:
LDXR Xt, [Xn|SP{,#0}]
STXR
独占内存访问指令 STXR Ws,Xt,
[Xn|SP{,#0}]
LDXP
多字节独占内存访问指令
LDXP Xt1,Xt2,[Xn|SP{,#0}]
STXP
STXP Ws,Xt1,Xt2, [Xn|SP{,#0}]
特别介绍一下:
一、栈的作用
1、栈通常用来保存:
①临时存储的数据,例如局部变量
②参数,函数调用过程中,如果传递的参数小于或等于8个,那么使用X0~X7通用寄存器来传递,大于8个,则需要使用栈来传递
2、为单个函数分配的栈空间,即从该函数栈底到栈顶这段空间,称为栈帧(FP)
sp: (Stack Pointer),栈顶寄存器,用于保存栈顶地址;
fp(x29): (Frame Pointer)为栈基址寄存器,用于保存栈底地址;
lr(x30): (Link Register) ,保存调用跳转指令 bl 指令的下一条指令的内存地址;
zr(x31): (Zero Register),xzr/wzr分别代表 64/32 位,其作用就是 0,写进去代表丢弃结果,读出来是 0;
pc: 保存将要执行的指令的地址(有操作系统决定其值,不能改写)