寄存器
通用寄存器
ARM64包含31个64bit寄存器,记作x0~x30
每个通用寄存器的低32bit可直接访问,记作w0~w30,例如x7的低32bit为w7
- x0:存储函数返回值、传递函数参数和临时存储变量
- x1~x7:用于传递函数参数和临时存储变量
- x8:间接结果寄存器,传递间接结果的地址,例如函数返回大型结构体时,由x8传递结构体地址
- x9~x15:父函数负责保存的临时寄存器,子函数可以任意修改
- x16 & x17:即IP0和IP1,作为临时寄存器用于函数内部的临时计算
- x18:保留给平台ABI(应用程序二进制接口)的寄存器,若平台没有给x18分配特殊用途则可作为普通临时寄存器使用
- x19~x28:子函数负责保存的临时寄存器,若子函数需使用,则必须负责在使用前保存其中的值,并在退出前恢复。父函数可以假设其在调用子函数前后不变
- x29:帧指针寄存器FP(Frame Pointer),指向当前函数栈帧的位置
- x30:链接寄存器LR(Link Register),存储函数调用和异常处理结束后需返回到的位置
函数调用
函数栈帧总是在对应函数内部自行创建、管理,而不是依赖父函数创建
Step1:建立栈帧 & Step2:保存现场(函数起始处)
stp x29, x30, [sp, -16]!
mov x29, sp
含义为:
sp = sp - 16ARM64指令集中栈向下增长,分配16字节栈空间。16字节对应两个寄存器中值的长度*(sp) = x29保存调用前x29的值*(sp + 8) = x30保存调用前x30的值x29 = sp更新x29中保存的当前函数栈帧
Step3:恢复现场(函数返回前)
ldp x29, x30, [sp], 16
ret
含义为:
x29 = *(sp)读取调用前x29的值x30 = *(sp + 8)读取调用前x30的值sp = sp + 16退栈ret返回到父函数
编译器处理函数调用时,常采用延迟栈帧初始化(Lazy Stack Frame Setup)优化。函数进入时不立刻建立栈帧,直到发现需要栈帧时才建立(有数组/大对象变量、寄存器数量不足、调用子函数、需要取地址等情况),从而减少指令数和内存I/O、提高分支性能。
ARM条件码/NZCV标志位

ldr:Load Register
将数据从内存加载到寄存器中
ldr{<size>}{<cond>} <Rt>, [<Rn>, <offset>]{!}
ldr{<size>}{<cond>} <Rt>, [<Rn>], <offset>
- <size>:B(字节)、H(半字)、SB(有符号字节)、SH(有符号半字),默认字(32位)
- <cond>:条件执行后缀,如EQ,NE。
- <Rt>:目标寄存器
- <Rn>:基址寄存器
- <offset>:立即数、寄存器或移位寄存器
- !:可选是否写回基址寄存器
示例
- 基址寻址:
LDR R1, [R0]从R0指向地址加载数据 - 基址+偏移:
LDR R1, [R0, #8]从 R0+8 地址加载数据,R0 不变 - 前变基寻址:
LDR R1, [R0, #4]!R0 = R0 + 4 后加载数据 - 后变基寻址:
LDR R1, [R0], #4加载数据后 R0 = R0 + 4 - 数据类型扩展:
LDRB R1, [R0]无符号字节LDRH R2, [R0]无符号半字LDRSB R3, [R0]有符号字节LDRSH R4, [R0]有符号半字
str:Store Register
将寄存器中的值写入内存中的指定地址,与ldr对应
STR{<size>}{<cond>} <Rt>, [<Rn>, <offset>]{!}
STR{<size>}{<cond>} <Rt>, [<Rn>], <offset>
{<size>}:可选的数据大小指定符,同ldr{<cond>}:可选的条件码后缀,同ldr<Rt>:源寄存器,其值将被写入内存<Rn>:基址寄存器,其值是内存访问的基地址<offset>:偏移量。立即数、寄存器或移位寄存器{!}:可选是否写回基址寄存器
cbz & cbnz:Campare and Branch if (Not) Zero
若寄存器的值为零/不为零,则跳转
cbz <Rt> <Label>
cbnz <Rt> <Label>
- <Rt>:目标寄存器
- <Label>:跳转标签
cmp:Compare
比较寄存器中或立即数的值,更新条件标志位。其后常使用beq、bne等指令进行条件跳转。
cmp <Rt1> <Rt2>
cmp <Rt1> #<imm>
- <Rt1> <Rt2>:存储进行比较的值的寄存器
- #<imm>:进行比较的立即数,0~4095
ccmp:Conditional Compare
根据条件对寄存器值和立即数进行比较,并更新条件标志位
ccmp <Xn|Wn>, #<imm>, #<nzcv>, <cond>
- <Xn|Wn>:参与比较的寄存器。
- #<imm>:立即数,用于与寄存器值比较。
- #<nzcv>:指定的标志位值。
- <cond>:条件码,决定是否执行比较。
若条件成立,则计算寄存器值与立即数的差值,更新条件标志位;
若条件不成立,则直接将标志位设置为#<nzcv>的值
stp:Store Pair
将两个通用寄存器的中的值同时存储到内存中。写入内存时,stp自动计算偏移量,将两个值存入连续的内存地址中。
stp <Wt1>, <Wt2>, [<Xn|SP>{, #<imm>}]{!}
stp <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}]{!}
- <Wt1>&<Wt2> :两个要存储的32位通用寄存器
- <Xt1>&<Xt2> :两个要存储的64位通用寄存器
- [<Xn|SP>] :存储的目标内存地址
- #<imm> :可选的偏移量
- !:存储的目标内存地址在SP中时可选,在存储前更新SP寄存器
ldp:Load Pair
与stp对应,从内存中加载两个通用寄存器的值。自动计算读取时的偏移量。若指令读取SP中的值且提供了立即数,则会在读取后更新SP寄存器的值
ldp <Wt1>, <Wt2>, [<Xn|SP>{, #<imm>}]
ldp <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}]
- <Wt1>&<Wt2> :两个要存储的32位通用寄存器
- <Xt1>&<Xt2> :两个要存储的64位通用寄存器
- [<Xn|SP>] :存储的目标内存地址
- #<imm> :可选的偏移量
ret:Return
从函数或过程返回,基本原理是将寄存器(通常是x30)中的值加载到PC中
ret {xn}
- xn:可选的寄存器,默认为x30。
sub:Subtraction
减法运算
sub{<cond>}{s} <Rd>, <Rs|imm>, {<Rs|imm>}
- <cond>:可选条件码
- <s>:可选是否更新条件标志位,subs更新标志位
- <Rd>:目标寄存器,将存储运算结果
- <Rs|imm>:两参数时,将寄存器/立即数/寄存器移位操作作为减数;三参数时为被减数
- {<Rs|imm>}:三参数时指定减数
示例
sub Rd, Rn ;//Rd -= Rn
sub Rd, Rn, #imm ;//Rd = Rn - imm
sub Rd, #imm ;//Rd -= 立即数
sub Rd, Rn, Rm ;//Rd = Rn - Rm

原来是这样,我完全搞懂了.jpg
另外祝贺楼主3/100啦ヾ(≧▽≦*)o
3/100😨😨
原来是这样,我完全搞不懂了.jpg
重读一遍发现自己也看不懂了(ó﹏ò。)