一些小注意点
- 汇编文件一般后缀名是 .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寄存器
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标志位时才能发生跳转。
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-R1十4
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
LDP指令
p是pair的简称,
往内存中写数据
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