一、汇编的组成
1.汇编指令:在内存中占用内存,执行一条汇编指令会让处理器进行相关运算
分类:数据处理指令,跳转指令,内存读写指令,状态寄存器传送指令,软中断产生指令,协助处理器指令
2.伪操作:不是汇编指令,不占用指令周期,起到声明作用
3.伪指令:不是汇编指令,占用指令内存,当执行伪指令会让处理器进行对应的运算操作,通常伪指令是一条或多条汇编指令的另外一种用法
4.注释:
单行注释:@,其他架构汇编注释可能是;
多行注释:/**/
条件编译:
.if 逻辑值
代码段
.else
代码段
.endif
二、汇编指令的基本格式
<opcode>{<cond>}{s} <Rd>, <Rn>, <shifter_operand>
<opcode>:汇编指令的指令码,由指令码决定现在是哪一个指令
cond:条件码,可以有可无,执行指令前先判断,满足才执行指令
s:指令码后加s,表示指令的运算结果会影响到CPSR寄存器的条件位
Rd:目标寄存器,指令运算结果会保存在目标寄存器中
Rn:第一操作寄存器,只能写寄存器,参与运算的第一个数值
shifter_operand:第二操作数,可以是寄存器,也可以是一个立即数
运算解释:先判断条件码对应条件是否满足,如满足则将第一操作数与第二操作数按指令码进行运算,运算的结果保存在目标寄存器中,并且结果影响CPSR条件位
三、数据搬移指令
1.mov{条件码} 目标寄存器,操作数vn
条件码可有可无,当存在条件码时,需满足条件才能1将操作数的数值搬移到目标寄存器
2.mvn{条件码} 目标寄存器,操作数
将操作数按位取反后的结果搬移到目标寄存器中
3.立即数
能够当作指令的一部分直接去执行的数据,操作数在当作指令的一部分执行时,需要对该操作数进行处理并保存到指令空间的[11:0]位中,如果处理完毕能够保存进去,说明该操作数是立即数。
处理方式:对该操作数进行循环右移偶数位,如果右移过程中,该操作数右移的值有在0-255这个范围内,说明该操作数是一个立即数,此时将循环右移的值保存在指令空间的[7:0]位,循环右移的偶数位数除以2的值保存到指令空间的[11:8]中(快速判断是否立即数:起始位为1和结束位为1之间的位数要小于7是立即数),当循环右移始终得不到0-255的数据,此时将其取反,如果取反值在0-255之间,该数据也是立即数
4.如果要将一个非立即数保存到寄存器中,可以使用伪指令LDR
四、数据移位指令
算术右移:除了最高符号位不变,最低位移出,最高位补0
逻辑右移:lsr{条件码},目标寄存器,第一操作寄存器,第二操作数
最低位移出,最高位补0,将第一操作寄存器的数值右移第二操作数对应的位数
循环右移:ror{条件码},目标寄存器,第一操作寄存器,第二操作数
最低位移出,补到最高位,将第一操作寄存器的数值循环右移第二操作数对应的位数
逻辑左移:lsl{条件码},目标寄存器,第一操作寄存器,第二操作数
将第一操作寄存器的数值左移第二操作数对应的位数
在书写操作数时可以使用c风格移位运算:如:mov r1,#(oxff>>4);
五、位运算指令
与:与0置0,与1不变
and{条件码},目标寄存器,第一操作寄存器,第二操作数
将第一操作寄存器和第二操作数进行按位与操作,结果保存到目标寄存器中
或:或1置1,或0不变
orr{条件码},目标寄存器,第一操作寄存器,第二操作数
将第一操作寄存器和第二操作数进行按位或操作,结果保存到目标寄存器中
异或:相同为0,相异为1
eor{条件码},目标寄存器,第一操作寄存器,第二操作数
将第一操作寄存器和第二操作数进行按位异或操作,结果保存到目标寄存器中
按位取反
mvn{条件码},目标寄存器,操作数
将操作数进行按位取反操作,结果保存到目标寄存器中
按位清0:想要运算结果为0,则给一个运算数据1
bic{条件码},目标寄存器,第一操作寄存器,第二操作数
将第一操作寄存器和第二操作数进行按位清零操作,结果保存到目标寄存器中
六、算数运算指令
1.加法指令:
add{条件码}{s}目标寄存器,第一操作寄存器,第二操作数
将第一操作数寄存器的值加第二操作数,结果保存到目标寄存器,如果在指令后加s,结果会影响CPSR条件位
adc{条件码}{s}目标寄存器,第一操作寄存器,第二操作数
将第一操作数寄存器的值加第二操作数再加上CPSR的c位值,结果保存到目标寄存器,如果在指令后加s,结果会影响CPSR条件位
2.减法指令:
sub{条件码}{s}目标寄存器,第一操作寄存器,第二操作数
将第一操作数寄存器的值减去第二操作数,结果保存到目标寄存器,如果在指令后加s,结果会影响CPSR条件位
sbc{条件码}{s}目标寄存器,第一操作寄存器,第二操作数
将第一操作数寄存器的值减去第二操作数再减去CPSR的c位值取反,结果保存到目标寄存器,如果在指令后加s,结果会影响CPSR条件位
3.乘法指令:mul{条件码}{s}目标寄存器,第一操作寄存器,第二操作数
将第一操作数寄存器的值乘以第二操作数,结果保存到目标寄存器,如果在指令后加s,结果会影响CPSR条件位
4.在32位的处理器上进行64位的数据运算:将64位数据保存两个寄存器中,先运算低32位,运算结果影响CPSR位,后运行高32位考虑CPSR位
七、比较指令
cmp 第一操作寄存器,第二操作数
进行两个数的比较,比较指令的本质时两个数的减法运算,运算结果影响CPSR条件位,一般比较指令会和条件码一起使用,先通过比较指令产生条件,后面的指令加上条件码,判断条件码对应的条件是否满足
八、跳转指令
1.修改PC值实现跳转,如果修改的的PC值不是4的倍数,处理器会将这个数值的最低两位设置为0,凑成4的整数倍
2.跳转指令
b label:程序跳转到标签lable位置去执行,只能实现跳转,LR寄存器不保存返回地址
bl label:程序跳转到标签label位置去执行,LR寄存器保存返回地址
九、内存读写指令
Keil调试过程中内存的查看
1.查看读写权限范围
2.查看内存内容
3.单寄存器内存读写指令
将一个寄存器的值写入内存中或者从内存中读取数值放在寄存器中
向内存中写入:
1)str 目标寄存器,[目标地址],将目标目标寄存器的4字节数据保存到目标地址对应的内存空间
2)strh 目标寄存器,[目标地址],将目标目标寄存器的2字节数据保存到目标地址对应的内存空间
3) strb 目标寄存器,[目标地址],将目标目标寄存器的1字节数据保存到目标地址对应的内存空间
从内存中读:
1)ldr 目标寄存器,[目标地址],从目标地址对应空间的空间中,读取4字节数据保存到寄存器中
2)ldrh 目标寄存器,[目标地址],从目标地址对应空间的空间中,读取2字节数据保存到寄存器中
3) ldrb 目标寄存器,[目标地址],从目标地址对应空间的空间中,读取1字节数据保存到寄存器中
单寄存器内存操作过程中的地址偏移:
1) str 目标寄存器,[基地址,偏移量],将目标目标寄存器的4字节数据保存到基地址+偏移量为首地址对应的内存空间
2) ldr 目标寄存器,[基地址,偏移量],从基地址+偏移量为首地址的内存中读取数据保存到目标寄存器
4.批量寄存器内存读写
通过指令将多个寄存器中的数据写入到内存或者从内存中读取多个数据保存到多个寄存器
写入到内存:
1) stm 目标地址,{寄存器列表},将寄存器列表中的每一个寄存器的值写入到目标地址对应的内存空间
从内存中读取:
1) ldm 目标地址,{寄存器列表},从目标地址对应的内存空间中读取多个数据保存到寄存器列表中的每一个寄存器中
注意:
寄存器列表书写模式可以使用“,”分割每个寄存器
如果寄存器编号是连续的,可以使用“-”连接头尾
无论寄存器列表的寄存器顺序是如何,始终都是小编号的寄存器对应低地址
批量寄存器的地址增长:
在操作多个寄存器时,只有一个寄存器保存操作的地址,正常情况下,操作完地址之后,保存操作地址寄存器里的地址要发生相应的增长,防止多次内存读写时,内存数据发生覆盖
写入到内存:
1) stm 目标地址!,{寄存器列表},将寄存器列表中的每一个寄存器的值写入到目标地址对应的内存空间,同时操作目标地址会改变
从内存中读取:
1) ldm 目标地址!,{寄存器列表},从目标地址对应的内存空间中读取多个数据保存到寄存器列表中的每一个寄存器中,同时操作目标地址会改变
指令不同后缀可让地址进行不同方向增长:
1)ia:先操作目标地址,再保存目标地址的寄存器的往地址大的方向增长
2)ib:先将保存目标地址的寄存器的往地址大的方向增长,再操作目标地址
3)da:先操作目标地址,再保存目标地址的寄存器的往地址小的方向增长
4)db:先将保存目标地址的寄存器的往地址小的方向增长,再操作目标地址
十、栈内存读写
栈是一段内存,是分配出来用于保存一些临时数据,通过SP栈指针寄存器保存栈顶地址
栈的分类:
增栈:压栈时,SP值往高地址方向增长
减栈:压栈时,SP值往地址低方向增长
空栈:压栈结束,栈指针寄存器对应的栈空间没有有效数据
满栈:压栈结束,栈指针寄存器对应的栈空间有有效数据
根据两种不同标准相互结合,分为:满增栈(FA),满减栈(FD),空增栈(EA),空减栈(ED)
ARM处理器操作内存时默认使用满减栈
满减栈的压栈与出栈
压栈:
push{寄存器列表},将寄存器列表中每一个寄存器的值压栈
stmdb {寄存器列表}
stmfd {寄存器列表}
出栈:
pop{寄存器列表},从栈内弹出数据保存到寄存器列表的每一个寄存器中
ldmia {寄存器列表}
ldmfd {寄存器列表}
十一、状态寄存器传送指令
状态寄存器CPSR保存程序相关状态,通过状态寄存器指令可读取状态寄存器的值或修改CPSR的值改变程序工作状态
读状态寄存器
MRS 目标寄存器,CPSR,将CPSR的数值读取到目标寄存器中
修改CPSR值
MSR CPSR,操作数,将操作数的数值写入到CPSR寄存器中
注意:在特权模式下可以修改CPSR的值切换到USER模式,但是USER模式下不可以通过修改CPSR的值切换到特权模式,只有在特定移除才可以从USER切换到其他特权模式
十二、软中断产生指令
1.swi 操作数,产生一个软中断,操作数是一个12位的立即数,用于表示不同的软中断
2.异常模式与异常源
异常模式:产生异常之后处理器进入的工作模式
异常源:引发处理器进入异常模式的源头就是异常源
ARM有5中异常模式,7种异常源
异常模式 | 异常源 |
FIQ | 触发FIQ中断 |
IRQ | 触发IRQ中断 |
SVC | 复位 |
SVC | 软中断 |
ABORT | 取数据异常 |
ABORT | 取指令异常 |
UNDEF | 遇到未定义的指令 |
3.异常向量表
异常向量表是一段内存,这段内存一般加载在硬件程序开头,异常向量表大小是32字节,分为8等分,一份对应一个异常源。在异常向量表中存储了索引异常源对应的异常处理程序指令,当触发异常后,处理器会根据异常源的类型在异常向量表中得到异常处理程序的位置,进而执行异常。每一个异常源在异常向量表中的位置是固定的。
4、异常处理过程分析
触发异常后,处理器做了四大步三小步完成异常处理的转变工作,该工作由处理器自动完成,程序员需要做的是编写异常处理程序,修改程序异常向量表
1)保存产生异常时的程序状态(CPSR)到对应异常的SPSR寄存器中
2)修改CPSR的数值切换程序工作状态
a.将程序的工作模式切换到对应对应的异常模式[4:0]
b.根据触发的异常的优先级,将FIQ和IRQ中断禁用[7:6]
c.处理器的工作状态切换到ARM状态[5]
3)将程序的返回地址保存到对应异常模式的LR寄存器中
4)修改PC的值到异常源所在异常向量表中位置
练习:使用汇编实现1-100的累加