寄存器
-
通用寄存器
- 64 bit 的 x0 ~ x28
- 32 bit 的 w0 ~ w28(属于x0 ~ x28的低32bit)
- x0 ~ x7 通常拿来存放函数的参数, 更多的参数使用堆栈来传递
- x0 通常拿来存放函数的返回值
-
程序计数器
-pc (Program Counter)
-
堆栈指针
- sp (Stack Pointer)
- fp (Frame Pointer) 也就是 x29
-
链接寄存器
- lr (link Register) 也就是 x30
-
程序状态寄存器
- cpsr (Current Program Status Register) 百度百科
- spsr (Saved Program Status Register)
指令
-
ret
- 函数返回 (相当于 return)
- 将 lr 寄存器中的值赋值给pc寄存器
-
mov
- MOV {条件} {S} 目的寄存器, 源操作数
-
add
- ADD {条件} {S} 目的寄存器 , 操作数1 操作数2
- ADD指令用于把两个操作数相加, 并将结果存放到目的寄存器中,操作数1: 应是一个寄存器, 操作数2可以是一个寄存器 被移位的寄存器, 或一个立即数
- 指令实例:
- ADD R0, R1, R2 : R0 = R1 + R2
-
sub
-
cmp
- 操作数1, 操作数2
- 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较, 同时更新 CPSR 中条件标志位的值, 该指令进行一次减法运算但不存储结果,只更改条件标志位,标志位表示的是操作数1 与 操作数2 的关系, (大, 小, 相等), 例如, 当操作数1 大于操作数数2, 则此后的有GT后缀的指令将可以执行
- 指令实例:
CMP R1, R0 :将寄存器R1的值与寄存器R0的值相减, 并根据结果设置CPSR的标志位 CMP R1, #100 :将寄存器R1的值与立即数100相减, 并根据结果设置CPSR的标志位
-
b
- 跳转指令
- b{条件} 目标地址
- b 指令是最简单的跳转指令, 一旦遇到一个B指令, ARM处理器将立即跳转到给定的目标地址,从那里继续执行,注意存储在跳转指令中的实际值是相对当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编来计算,(参考寻址方式中的相对寻址), 它是24位有符号数, 左移两位后有符号扩展为32位, 表示的有效偏移为26位(前后32MB空间)以下指令
B Label :程序无条件跳转到符号 Label 执行 CMP R1, #0 :当CPSR寄存器中的z条件码置位时, 程序跳转到符号Label处执行 BEQ Label
-
bl (类似函数调用)
- BL{条件} 目标地址
- BL 是 另一个跳转指令, 但是跳转之前 会在寄存器R14中保存PC的当前内容, 因此, 可以通过R14 的内容重新加载到PC中, 来返回到跳转指令之后的那个指令执行, 该指令是实现子程序调用的一个基本常用的手段, 以下指令:
BL Label :当程序无条件跳转到标号 Label 处执行时, 同时将当前的PC值保存到R14中
-
条件域
- EQ : equal 相等
- NE : not equal 不相等
- GT : great than 大于
- GE : great or equal 大于等于
- LT : less than 小于
- LE : less or equal 小于等于
-
内存操作
-
load 从内存中读取数据
- ldr, ldur (ldr 是正偏移, ldur是负偏移)
- ldp (p 是 pair的简称 (对))
- 从寄存器中获取成对的数据存入目标存储器中
-
store 往内存中写入数据
- str, stur
- stp
- 零寄存器 里面存储的值为 0
- wzr (32bit Word Zero Register) 8个字节
- xzr (64bit ) 16个字节
-
立即寻址
立即寻址也叫立即数寻址, 这是一种特殊的寻址方式, 操作数本身就在指令中给出, 只要取出指令也就取到了操作数, 这个操作数被称为立即数, 对应的寻址方式也就叫做立即寻址, 例如以下指令:
ADD R0, R0, #1 : R0 <-- R0+1
ADD R0, R0, #0x3f : R0 <-- R0+0x3f
在以上两条指令中, 第二个源操作数即为立即数, 要求以 "#" 为前缀, 对于以16进制表示的立即数 还要求在"#" 后加上"0X' 或 "&'
寄存器寻址
寄存器寻址就是利用寄存器中的数值作为操作数, 这种寻址的方式是各类微处理器经常采用的一种方式, 也是一种执行效率较高的寻址方式, 一下指令:
ADD R, R1, R2 :R0 <-- R1+R2
该指令的执行效果是将寄存器R1和R2的内容相加, 其结果存放在寄存器R0中.
寄存器间接寻址
寄存器间接寻址就是以寄存器中的值作为操作数的地址, 而操作数本身存放在存储器中. 例如一下指令:
ADD R0, R1, [R2] : R0 <-- R1 + [R2]
LDR R0, [R1] : R0 <-- [R1]
STR R0, [R1] : [R1] <-- R0
在第一条指令中, 以寄存器R2的值作为操作数的地址, 在存储器中取得一个操作数后与R1相加, 结果存入寄存器R0中.
第二条指令将以R1的值为地址的存储器中的数据传送到R0中
第三条指令将R0的值传送到以R1的值为地址的存储器中
基址变址寻址
基址变址寻址就是寄存器(该寄存器一般称作基址寄存器)的内容与指令中给出地址偏移量相加,从而得到一个操作数的有效地址, 变址寻址常用于访问某基地址附近的地址单元, 采用变址寻址的指令常见有以下几种形式 如下所示:
LDR R0, [R1, #4] :R0 <-- [R1+4]
LDR R0, [R1, #4]! :R0 <-- [R1+4], R1 <--R1+4
LDR R0, [R1], #4 :R0 <--[R1], R1 <--R1+4
LDR R0, [R1, R2] :R0 <-- [R1+R2]
在第一条指令中,将寄存器R1的内容加上4形成操作数的有效地址, 从而取得操作数存入寄存器R0中
第二条指令中,将寄存器R1的内容加上4形成操作数的有效地址,从而取得操作数存入寄存器R0中,然后,R1的内容自增4个字节
在第三条指令中,以寄存器R1的内容作为操作数的有效地址,从而取得操作数存入寄存器R0中,然后, R1的内容自增4个字节
在第四条指令中, 将寄存器R1的内容加上寄存器R2的内容形成操作数的有效地址, 从而取得操作数存入寄存器R0中.
多寄存器寻址
采用多寄存器寻址方式, 一条指令可以完成多个寄存器值的传递, 这种寻址方式可以用一条指令完成传送最多16个通用寄存器的值, 一下指令:
LDMIA R0, {R1, R2, R3, R4} :R1 <--[R0]
:R2 <--[R0+4]
:R3 <--[R0+8]
:R4 <--[R0+12]
该指令的后缀 IA 表示在每次执行完加载/存储操作后, R0按字节长度增加, 因此, 指令可以将连续存储单元的值传送到 R1~R4
相对选址
与基址变址寻址方式相似, 相对寻址以程序计数器PC的 当前值为基地址, 指令中的地址标号作为偏移量, 将两者相加之后得到操作数的有效地址, 一下程序段完成子程序的调用和返回, 跳转指令BL采用了相对寻址的方式.
BL NEXT :跳转到子程序NEXT处执行
......
NEXT
......
MOV PC, LR :从子程序返回
堆栈寻址
堆栈是一种数据结构 按先进先出(FIFO) 的方式工作, 作用一个称作堆栈指针的专用寄存器指示当前的操作位置, 堆栈指针总是指向栈顶.
当堆栈指针向最后压入堆栈的数据时, 成为满堆栈(FULL STACK) 而当堆栈指针指向下一个将要放入数据的空位置时, 成为空堆栈(Empty Stack)
同时, 根据堆栈的生成方式 ,又可以分为递增堆栈(Ascending Stack) 和 递减堆栈(Decending Stack) 当堆栈由低地址向高地址生成时, 称为递增堆栈 当堆栈有高地址向低地址生成时, 称为递减堆栈, 这样就有四种类型的堆栈工作方式, ARM微处理器支持这四种类型的堆栈工作方式.
-- 满递增堆栈: 堆栈指针指向最后压入的数据, 且有低地址向高地址生成
-- 满递减堆栈: 堆栈指针指向最后压入的数据, 且由高地址向低地址生成
-- 空递增堆栈: 堆栈指针指向下一个将要放入数据的空位置, 且由低地址向高地址生成
-- 空递减堆栈: 堆栈指针执行下一个将要放入数据的空位置, 且由高地址向低地址生成
iOS汇编
-
真机: arm64 汇编
- 寄存器
- 指令
- 堆栈
-
模拟器: x86 汇编