ARM --- 汇编指令
最佳答案 问答题库588位专家为你答疑解惑
2 汇编
2.1 汇编基础
2.1.1 汇编文件中的符号信息
1.位操作:伪操作不是一条指令,知识给编译器使用,知道编译器如何对代码进行编译,不占用代码段的任何空间
.text
.gloal
.end
.data
.word
.short
.byte
.if
.else
.endif ....
2.汇编指令:汇编指令汇编编译器编译成32位的机器码,放到代码段空间,汇编指令可以完成特定的功能
3.伪指令:本身不是一条汇编指令,编译器可以将其编译生成多条指令来完成一条伪指令的功能
4.注释: @单行注释 与编译器有关
多行注释:/**/ .if .endif
2.1.2 最基本的汇编指令的语法格式
<opcode>{cond}{s} Rd, Rn , oprand_shifter
<opcode> 指令码 指令名
{cond} 条件码,实现指令的有条件执行
{s} 状态位 加s,指令的执行结果影响CPSR 寄存器的NZCV位的变化
Rd:目标寄存器
Rn:第一个操作寄存器
oprand_shifter:第二个操作数 可以是寄存器 可以是立即数 可以是经移位的寄存器
不区分大小写
2.2 汇编指令
2.2.1数据操作指令
2.2.1.1数据搬移指令
mov mvn
mov mvn@没有第一操作数@mov{cond}{s} Rd, oprand_shifter@mvn{cond}{s} Rd, oprand_shifter.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@函数的入口地址mov r0,#01 @汇编指令 第二操作数为立即数mov r1 ,r0 @第二操作数为寄存器mvn r2,#0xff @第二操作数为立即数 ,对第二操作数取反在存入stop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束
立即数
存放在0-11位上,其中0-7位存放0-255之间的数,8-11位上存放偏移量/2
如何判断某个数是立即数:
首先通过要判断的那个数,找到一个0-255(0x00-0xff)之间的数,然后将这个数据循环右移偶数维,如果可以得到要判断的那个数,说明是立即数
指令不同,立即数规则不同
有效数
如果一个数取反后是立即数说明这个数是有效数,也可以存储
伪指令
ldr Rd , =任意32位的整数
ldr r0, = 0x12345678
2.2.1.2算数运算指令
add:普通的加法指令,不需要考虑进位标志位
adc:需要考虑进位标志位
.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@练习,实现两个64位数据的加法运算@第一个64位的数据存到r0(第32位),r1(高32位)@第二个64位的数据存到r2,r3@结果存在r4 ,r5mov r0, #0xFFFFFFFEmov r1, #3mov r2, #4mov r3, #5@完成低32位数据的加法@要加s,这样溢出才会影响SPSR的C位,进位adds r4,r0,r2 @r4 = 0xFFFFFFFE + 0x4 = 0x2@完成高32位数据的加法adc r5,r1,r3 @r5 = 0x3 + 0x5 + C = 0x9stop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束
sub:普通的减法法指令,不需要考虑借位标志位
sbc:需要考虑借位标志位
.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@练习,实现两个64位数据的加法运算@第一个64位的数据存到r0(第32位),r1(高32位)@第二个64位的数据存到r2,r3@结果存在r4 ,r5mov r0, #0xFFFFFFFEmov r1, #3mov r2, #4mov r3, #5@完成低32位数据的加法@要加s,这样溢出才会影响SPSR的C位,进位adds r4,r0,r2 @r4 = 0xFFFFFFFE + 0x4 = 0x2@完成高32位数据的加法adc r5,r1,r3 @r5 = 0x3 + 0x5 + C = 0x9stop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束
mul:乘法指令
乘法指令的操作数只能是寄存器
.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名mov r0, #3mov r1, #4mul r2,r0,r1 @r2= 0x3 * 0x4 = 0xcstop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束
div:除法指令(ARM-V8架构支持,V7架构不支持)
格式:
<opcode>{cond}{s} Rd,Rn,oprand_shifter
2.2.1.3移位操作指令
指令码
lsl:逻辑左移/无符号数左移 logical(逻辑) shift(转移) left(左)
lsr:逻辑右移/无符号数右移
asr:算术右移/有符号数右移
ror:循环右移
.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@函数的入口地址mov r0, #0xFF@按位左移,低位补0lsl r1,r0,#0x4 @将r0的值左移4位后赋值给r1@按位右移,高位补0lsr r2,r1,#4@算术右移,高位补符号位mov r0 , #0xFF000000asr r3,r0,#4@循环右移,低位移除,补到高位ror r4,r3,#5 @r4 = 0x07F80000stop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束@第二个操作数可以是移位操作寄存器mov r0,r1, lsl #4 @ r0 = r1<<4
指令格式
<opcode>{cond}{s} Rd,Rn,oprand_shifter
2.2.1.4位运算指令
and:按位与运算
orr:按位或运算
eor:按位异或运算
bic:按位清除
.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@函数的入口地址mov r0, #0xFF@按位左移,低位补0lsl r1,r0,#0x4 @将r0的值左移4位后赋值给r1@按位右移,高位补0lsr r2,r1,#4@算术右移,高位补符号位mov r0 , #0xFF000000asr r3,r0,#4@循环右移,低位移除,补到高位ror r4,r3,#5 @r4 = 0x07F80000stop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束@第二个操作数可以是移位操作寄存器mov r0,r1, lsl #4 @ r0 = r1<<4
2.2.1.5比较指令
cmp:比较两数的大小
指令格式
cmp{cond} Rn,oprand_shifter
注意:
比较指令的本质就是做减法运算
指令没有目标寄存器,只有第一个操作寄存器和第二个操作数
指令的执行结果最终影响的是cpsr的NZCV位,并且不需要加s
比较指令和条件码配合使用
.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@函数的入口地址ldr r1,=0x000000FFldr r0,=0x0000FFFFcmp r0,r1stop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束@小于:N置1@大于:C置1@等于:Z置1,C置1
2.2.2 跳转指令
b/bl{cond} Lebel(标签/汇编函数名):跳转到Lebel标签下的第一条指令
Label:汇编指令
-
跳转指令的本质就是修改PC值
-
有去有回就用bl,函数调用
-
有去无回就是用b,stop: b stop
.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@函数的入口地址mov r0, #3mov r1, #4@调用汇编函数bl add_func @自动保存调准质量的下一条指令的地址到LR中@让PC执行函数的入口地址,nop @空指令@ldr pc , =stopb stop @跳出循环@定义汇编的函数add_func:add r0,r0,r1mov pc,lrstop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束
2.2.3 load/Store内存读写指令
1>单寄存器操作指令
ldr:将内存中的数据读到寄存器中
str:将寄存器中的数据写道内存中
ldrh:一次只能读写半字 2字节
strh:一次只能读写半字 2字节
ldrb:一次读写一字节
ldrb:一次读写一字节
ld:load
st:store
r:register
格式:
ldr{cond} Rd, [Rm]
Rm 寄存器中的数据将被看出一个内存的地址,将[Rm]指向的内存空间中的数据读到Rd寄存器
str{cond} Rd, [Rm]
Rm 寄存器中的数据将被看出一个内存的地址,将Rd寄存器中的数据写到[Rm]指向的地址
.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@函数的入口地址@不严谨ldr r0,=0x40000800ldr r1,=0x12345678str r1,[r0]ldr r2,[r0]stop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束
@ldr和str指令的特定用法@将[Rm,#num]指向的地址空间的数据,读到Rd寄存器中,@Rm中的地址不变ldr/ldrh/ldtd Rd,[Rm,#num] @将[RM]指向的地址空间的数据,读到Rd寄存器中@同时更新Rm中的地址,Rm=Rm+numldr/ldrh/ldtd Rd,[Rm],#num@将[RM+num]指向的地址空间的数据,读到Rd寄存器中@同时更新Rm中的地址,Rm=Rm+num@!表示更新Rm寄存器中的地址ldr/ldrh/ldtd Rd,[Rm,#num]!@将Rd寄存器中的数据写到[Rm+num]指向的地址空间中@Rm中的地址不变str/strh/strd Rd,[Rm,#num] @将Rd寄存器中的数据写到[Rm]指向的地址空间中@同时更新Rm中的地址,Rm=Rm+numstr/strh/strd Rd,[Rm],#num@将Rd寄存器中的数据写到[Rm,#num]指向的地址空间中@同时更新Rm中的地址,Rm=Rm+num@!表示更新Rm寄存器中的地址str/strh/strd Rd,[Rm,#num]!
.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@函数的入口地址@不严谨ldr r0,=0x40000800ldr r1,=0x12345678ldr r2,=0x22222222ldr r3,=0x33333333str r1,[r0,#4]str r2,[r0],#4str r3,[r0,#4]!ldr r0,=0x40000800ldr r4,[r0,#4]ldr r5,[r0],#4ldr r6,[r0,#4]!stop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束ldr/str指令中的num必须是4的整数倍ldrh/strh指令中num必须是2的整数倍ldrb/strb指令中的num必须是1的整数倍
2>多寄存器操作指令
m:mutil
ldm:将内存空间中连续的多个数据督导多个寄存器中
stm:将多个寄存器中的数据写到连续的内存空间中
格式:
ldm/stm Rm,{寄存器列表}
-
Rm寄存器中的数据将被看出内存的地址
-
寄存器中的寄存器如果连续就是用-隔开,如果不连续就用,隔开
-
寄存器列表中的寄存器要求从小到达的编号进行书写
3>栈操作指令
栈的种类:
增栈:压栈之后栈指针向高地址移动
减栈:压栈之后栈指针向低地址移动
空栈:当前栈指针指向的空间没有有效的数据,可以先进性压栈,然后将栈指针移动到下一个空的位置
满栈:当前栈指针指向的空间由有效的数据,需要先移动栈指针指向一个没有有效数据的空间然后再压入数据之后此时栈指针指向的空间又有有效数据
栈的操作方式:4种
满赠栈:Full Ascending stmfa/ldmfa
满减栈:Full Descending stmfd/ldmfd
空增栈:Empty Ascending stmea/ldmea
空减栈:Empty Decending stmed/lmed
ARM处理器默认采用的是满减栈
格式:
ldmfd/stmfd sp!,{寄存器列表}
-
sp寄存器中的数据将被看成指向的栈空间的地址
-
寄存器中的寄存器如果连续就是用-隔开,如果不连续就用,隔开
-
寄存器列表中的寄存器要求从小到达的编号进行书写
-
每次压栈或者出栈之后都需要更改sp寄存器中记录的地址
.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@函数的入口地址@初始化栈指针ldr sp,=0x40000820mov r0,#0x100mov r1,#0x200bl add_funcladd r2,r0,r1 @r2 = r0 + r1 = 0x300b stopadd_funcl:stmfd sp!,{r0-r1} @压栈保存现场mov r0,#0x300mov r1,#0x400add r3,r0,r1 @r3 = r0 + r1 = 0x700ldmfd sp!,{r0-r1} @出栈恢复现场mov pc,lrstop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束
2.2.4 特殊功能寄存器读写指令
msr :将普通寄存器中国的数据写到特殊寄存器中
mrs:将特殊寄存器中国的数据写到普通寄存器中
msr cpsr,#num/Rm:将一个立即数或者寄存器中的值赋值给cpsr寄存器
mrs Rd,cpsr :将cpsr寄存器中的值赋值给Rd寄存器
系统上电默认处于svc模式,修改cpsr寄存器的模式位(M[4:0])位,切换到用户模式
CPSR中的默认值为0xD3 1101 0011
修改为用户模式
CPSR中的默认值为0xD0 1101 0000
.text @代码段.global _start @将_start标签声明为一个全局的函数_start: @_start:标签的定义,等价于c语言的函数名@函数的入口地址@不严谨@msr cpsr , #0xD0 @方法2mrs r0,cpsrbic r0,r0,#0x1Forr r0,r0,#0xD0msr cpsr,r0stop: @stop标签b stop @跳转指令,跳转到stop标签下的指令 类似goto@裸机的程序中必须有一个死循环.end @代码段结束
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"ARM --- 汇编指令":http://eshow365.cn/6-16894-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!
- 上一篇: MySQL中的 增 删 查 改(CRUD)
- 下一篇: beego-简单项目写法--路径已经放进去了