2.ARM64常见的指令

119 阅读9分钟

一些小注意点

  • 汇编文件一般后缀名是 .asm ,简写可以写成 .s
  • 汇编的注释一般使用 ; xcode里面可以用 //

MOVE指令

MOV指令的格式为:
MOV{条件} {S} 目的寄存器,源操作数
MOV 指令可完成从另一个寄存器,被移位的寄存器或者立即数加载到目的寄存器。其中 S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S时,指令不更新CPSR中条件标志位的值。 指令示例:

MOV X1, X0         ;将寄存器XO的值传送给X1
MOV PC, X14        ;将寄存器X13的值传送到PC,常用于子程序返回
MOV X1,X0,LSL#3    ;将寄存器X0的值左移3位后传送到X1

自己的理解:其实MOV指令就是将后面寄存器的值放到前面的寄存器。

RET指令

RET指令就是返回,相当于高级语言中的return

ADD指令

ADD 指令的格式为:
ADD{条件}{S} 目的寄存器,操作数1,操作数2 ADD 指令用于将两个操作数相加,并且将结果存放到目的寄存器中,第一个操作数只能是一个寄存器,第二操作数更灵活一些,可以是一个寄存器,被移位的寄存器,或一个立即数 指令示例:

ADD X0, X1, W2    ;X0 = X1 + X2
ADD X0, X1, #256  ;w0 = X1 + 256
ADD X0,X2,X3,LSL#1 ; X0 = X2 + (W3 << 1)

SUB指令

SUB指令的格式为: SUB{条件}{S} 目的寄存器,操作数1,操作数2
SUB指令用于把操作数1减去操作数2,并将结果存放到目的寄存器中。操作数1应该是一个寄存器,第二操作数更灵活一些,可以是一个寄存器,被移位的寄存器,或一个立即数。该指令用于有符号数或无符号数的减法运算。
指令示例:

SUB X0, X1, X2    ;X0 = X1 - X2
SUB X0, X1, #256  ;X0 = X1 - 256
SUB X0,X2,X3,LSL#1 ; X0 = X2 - (X3 << 1)

CMP指令

CMP 指令的格式为: CMP{条件} 操作数1,操作数2
CMP将两个寄存器相减,相减的结果会影响cpsr寄存器的标志位
指令示例:

CMP X1,X0 ;将寄存器X1的值与寄存器W0的值相减,并根据结果设置CPSR的标志位
CMP X1,#100 ;将寄存器X1的值与立即数100相减,并根据结果设置CPSR的标志位

CPSR寄存器

image.png

image.png

B指令

B 指令的格式为: B{条件} 目标地址
B指令是最简单的跳转指令。一旦遇到一个B指令,ARM处理器将立即跳转到给定的目标地址,从那里继续执行. 类似于c语言的goto
指令示例:

b mycode ;跳到mycode部分的代码执行
move x0, #0x5
mycode:
mov x1, #0x6

上面的示例是没有条件的跳转,如果想要根据条件进行跳转,这里的条件其实还是判断CPSR寄存器。这里的条件需要引出一个专业名词叫条件域。
其中我们常用的if else 就是汇编底层就是用B指令实现的。

条件域

当处理器工作在ARM状态时,几乎所有的指令均根据CPRS中的条件码的状态和指令的条件域有条件的执行。当指令的执行条件满足时,指令被执行,否则指令被忽略。
每一条ARM指令包含4位的条件码,位于指令的最高4位【31:28】。条件码共有16种,每种条件码可用两个字符表示,这两个字符可以添加在指令助记符的后面或者指令同时使用。例如,跳转指令B后面可以加上后缀EQ则表示‘相等则跳转‘,即当CPSR中的Z标志位时才能发生跳转。

image.png

BL指令

BL 指令的格式为: BL{条件} 目标地址
BL 是另外一个跳转指令,但跳转之前,会在寄存器X14中保存PC的当前内容,因此,可以通过将X14的内容重新加载到PC中,来返回到跳转指令之后的那条指令执行。该指令时实现子程序调用的一个基本但常用的手段。

BL Label ;当程序无条件跳转到符号Label处执行时,同时将当前的PC保存到X14中

B指令和BL指令的区别是跳转到别的地方就不返回到之前的地方了,BL还可以返回到当前的下一条继续执行。BL更像函数调用,B指令里面写了RET指令也没用,BL指令里面的RET才有效
BL的底层做了什么事? 1.将当前跳转指令后的下一条指令存到lr寄存器里面 2.跳转到标记处开始执行代码

在当前跳转的指令执行完之后,也就是执行 RET指令,RET指令本质是什么,是将LR寄存器的地址复制给PC,PC代表cpu正要执行的指令,这样PC就去执行跳转后的下一条了。

寻址方式

1.立即寻址

立即寻址也叫立即数寻址,这是一种特殊的寻址方式,操作数本身就在指令中给出,只要取出指令就取到了立即数。这个操作数被称为立即数,对应的方式叫做立即寻址。

ADD RO,RO,#1 ;RO-RO十1
ADD RO,RO,#0x3f ;RO-R0+0x3f

在以上两条指令中,第二个源操作数即为立即数,要求以“#”为前缀,对于以十六进制表示的立即数,还要求在“#”后加上“0x”或“&”

2.寄存器寻址

寄存器寻址就是利用寄存器中的数值作为操作数,这种寻址方式是各类微处理器经常采用的种方式,也是一种执行效率较高的寻址方式。以下指令:

ADD RO,R1,R2 ;RO-R1+R2

该指令的执行效果是将寄存器R1和R2的内容相加,其结果存放在寄存器R0中。

3.寄存器间接寻址

寄存器间接寻址 寄存器间接寻址就是以寄存器中的值作为操作数的地址,而操作数本身存放在存储器中。例如以下指令:

ADD RO,R1,[R2] ;RO-RI十[R2]
LDR RO, [RI]  ;RO-[RI]
STR RO, [RI]  ;[R1]-RO

在第一条指令中,以寄存器 R2的值作为操作数的地址,在存储器中取得一个操作数后与 RI 相加,结果存入寄存器 RO 中。 第二条指令将以 R1的值为地址的存储器中的数据传送到 RO 中。 第三条指令将 RO 的值传送到以 RI的值为地址的存储器中。

3. 基址变址寻址

基址变址寻址就是将寄存器(该寄存器一般称作基址寄存器)的内容与指令中给出的地址偏移量相加,从而得到一个操作数的有效地址。变址寻址方式常用于访问某基地址附近的地址单元。 采用变址寻址方式的指令常见有以下几种形式,如下所示:

LDR RO[R1,#4]    ;RO-[R1十4]
LDR RO,[R1,#4]!    ;RO-[R1十4]RI-R1+4
LDR RO[R1]#4    ;RO-[R1]RI-R14
LDR RO,[R1,R2]     ;RO-[RI+R2]

在第一条指令中,将寄存器 R1 的内容加上4形成操作数的有效地址,从而取得操作数存入寄存器 RO 中。 在第二条指令中,将寄存器 R1 的内容加上4形成操作数的有效地址,从而取得操作数存入寄存器 RO 中,然后,R1 的内容自增4个字节。 在第三条指令中,以寄存器R1 的内容作为操作数的有效地址,从而取得操作数存入寄存器 RO中,然后,R1 的内容自增4个字节。 在第四条指令中,将寄存器 R1 的内容加上寄存器 R2的内容形成操作数的有效地址,从而取得操作数存入寄存器 RO 中。

从内存中读数据

load,从内存中状态数据

LDR指令

LDR 指令的格式为: LDR{条件} 目标寄存器,<寄存器地址>
LDR 指令用于将存储器中将一个寄存器的数据作为地址,找到这个数据传送到目的寄存器中。该指令通常用于存存储器中读取64位数据到通用寄存器中,然后对数据进行处理。
指令示例:

LDR WO,[W1] 

上述指令代表的是从 W1这个寄存器里面取出来一个值,这个值作为地址,然后连续取一块空间的数据给W0,究竟要取几个呢,取决于前面的寄存器,比方说这里是W0是64位的,那么需要的就是8个。

LDUR指令

LDUR 如果立即数有负数,用LDUR,如果是正数就用LDR

image.png

image.png

LDP指令

p是pair的简称, image.png

往内存中写数据

store,往内存中存储数据

STR 指令

STR 指令的格式为: STR{条件}源寄存器,<存储器地址> STR 指令用于从源寄存器中将一个64位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令 LDR。 指令示例:

STR RO,[R1]#8 ;将 RO 中的字数据写入以 R1 为地址的存储器中,并将新地址 R1+8 写入 R1.
STR RO,[R1,#8] ;将 RO 中的字数据写入以 R1+8 为地址的存储器中。

STUR 指令

如果立即数有负数,用STUR,如果是正数就用STR

STP 指令

image.png