1.位操作:伪操作不是一条指令,知识给编译器使用,知道编译器如何对代码进行编译,不占用代码段的任何空间
.text
.gloal
.end
.data
.word
.short
.byte
.if
.else
.endif ....
2.汇编指令:汇编指令汇编编译器编译成32位的机器码,放到代码段空间,汇编指令可以完成特定的功能
3.伪指令:本身不是一条汇编指令,编译器可以将其编译生成多条指令来完成一条伪指令的功能
4.注释: @单行注释 与编译器有关
多行注释:/**/ .if .endif
{cond} 条件码,实现指令的有条件执行
{s} 状态位 加s,指令的执行结果影响CPSR 寄存器的NZCV位的变化
Rd:目标寄存器
Rn:第一个操作寄存器
oprand_shifter:第二个操作数 可以是寄存器 可以是立即数 可以是经移位的寄存器
不区分大小写
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
add:普通的加法指令,不需要考虑进位标志位
.text @代码段
.global _start @将_start标签声明为一个全局的函数
_start: @_start:标签的定义,等价于c语言的函数名
@练习,实现两个64位数据的加法运算
@第一个64位的数据存到r0(第32位),r1(高32位)
@第二个64位的数据存到r2,r3
@结果存在r4 ,r5
mov r0, #0xFFFFFFFE
mov r1, #3
mov r2, #4
mov r3, #5
@完成低32位数据的加法
@要加s,这样溢出才会影响SPSR的C位,进位
adds r4,r0,r2 @r4 = 0xFFFFFFFE + 0x4 = 0x2
@完成高32位数据的加法
adc r5,r1,r3 @r5 = 0x3 + 0x5 + C = 0x9
stop: @stop标签
b stop @跳转指令,跳转到stop标签下的指令 类似goto
@裸机的程序中必须有一个死循环
.end @代码段结束
.text @代码段
.global _start @将_start标签声明为一个全局的函数
_start: @_start:标签的定义,等价于c语言的函数名
@练习,实现两个64位数据的加法运算
@第一个64位的数据存到r0(第32位),r1(高32位)
@第二个64位的数据存到r2,r3
@结果存在r4 ,r5
mov r0, #0xFFFFFFFE
mov r1, #3
mov r2, #4
mov r3, #5
@完成低32位数据的加法
@要加s,这样溢出才会影响SPSR的C位,进位
adds r4,r0,r2 @r4 = 0xFFFFFFFE + 0x4 = 0x2
@完成高32位数据的加法
adc r5,r1,r3 @r5 = 0x3 + 0x5 + C = 0x9
stop: @stop标签
b stop @跳转指令,跳转到stop标签下的指令 类似goto
@裸机的程序中必须有一个死循环
.end @代码段结束
乘法指令的操作数只能是寄存器
.global _start @将_start标签声明为一个全局的函数
_start: @_start:标签的定义,等价于c语言的函数名
mov r0, #3
mov r1, #4
mul r2,r0,r1 @r2= 0x3 * 0x4 = 0xc
stop: @stop标签
b stop @跳转指令,跳转到stop标签下的指令 类似goto
@裸机的程序中必须有一个死循环
.end @代码段结束
div:除法指令(ARM-V8架构支持,V7架构不支持)
格式:
指令码
.text @代码段
.global _start @将_start标签声明为一个全局的函数
_start: @_start:标签的定义,等价于c语言的函数名
@函数的入口地址
mov r0, #0xFF
@按位左移,低位补0
lsl r1,r0,#0x4 @将r0的值左移4位后赋值给r1
@按位右移,高位补0
lsr r2,r1,#4
@算术右移,高位补符号位
mov r0 , #0xFF000000
asr r3,r0,#4
@循环右移,低位移除,补到高位
ror r4,r3,#5 @r4 = 0x07F80000
stop: @stop标签
b stop @跳转指令,跳转到stop标签下的指令 类似goto
@裸机的程序中必须有一个死循环
.end @代码段结束
@第二个操作数可以是移位操作寄存器
mov r0,r1, lsl #4 @ r0 = r1<<4
指令格式
.text @代码段
.global _start @将_start标签声明为一个全局的函数
_start: @_start:标签的定义,等价于c语言的函数名
@函数的入口地址
mov r0, #0xFF
@按位左移,低位补0
lsl r1,r0,#0x4 @将r0的值左移4位后赋值给r1
@按位右移,高位补0
lsr r2,r1,#4
@算术右移,高位补符号位
mov r0 , #0xFF000000
asr r3,r0,#4
@循环右移,低位移除,补到高位
ror r4,r3,#5 @r4 = 0x07F80000
stop: @stop标签
b stop @跳转指令,跳转到stop标签下的指令 类似goto
@裸机的程序中必须有一个死循环
.end @代码段结束
@第二个操作数可以是移位操作寄存器
mov r0,r1, lsl #4 @ r0 = r1<<4
指令格式
cmp{cond} Rn,oprand_shifter
注意:
比较指令的本质就是做减法运算
指令没有目标寄存器,只有第一个操作寄存器和第二个操作数
指令的执行结果最终影响的是cpsr的NZCV位,并且不需要加s
比较指令和条件码配合使用
.text @代码段
.global _start @将_start标签声明为一个全局的函数
_start: @_start:标签的定义,等价于c语言的函数名
@函数的入口地址
ldr r1,=0x000000FF
ldr r0,=0x0000FFFF
cmp r0,r1
stop: @stop标签
b stop @跳转指令,跳转到stop标签下的指令 类似goto
@裸机的程序中必须有一个死循环
.end @代码段结束
@小于:N置1
@大于:C置1
@等于:Z置1,C置1
Label:汇编指令
跳转指令的本质就是修改PC值
有去有回就用bl,函数调用
有去无回就是用b,stop: b stop
.text @代码段
.global _start @将_start标签声明为一个全局的函数
_start: @_start:标签的定义,等价于c语言的函数名
@函数的入口地址
mov r0, #3
mov r1, #4
@调用汇编函数
bl add_func @自动保存调准质量的下一条指令的地址到LR中
@让PC执行函数的入口地址,
nop @空指令
@ldr pc , =stop
b stop @跳出循环
@定义汇编的函数
add_func:
add r0,r0,r1
mov pc,lr
stop: @stop标签
b stop @跳转指令,跳转到stop标签下的指令 类似goto
@裸机的程序中必须有一个死循环
.end @代码段结束
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,=0x40000800
ldr r1,=0x12345678
str 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+num ldr/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+num str/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,=0x40000800 ldr r1,=0x12345678 ldr r2,=0x22222222 ldr r3,=0x33333333 str r1,[r0,#4] str r2,[r0],#4 str r3,[r0,#4]! ldr r0,=0x40000800 ldr r4,[r0,#4] ldr r5,[r0],#4 ldr r6,[r0,#4]! stop: @stop标签 b stop @跳转指令,跳转到stop标签下的指令 类似goto @裸机的程序中必须有一个死循环 .end @代码段结束 ldr/str指令中的num必须是4的整数倍 ldrh/strh指令中num必须是2的整数倍 ldrb/strb指令中的num必须是1的整数倍
m:mutil
ldm:将内存空间中连续的多个数据督导多个寄存器中
stm:将多个寄存器中的数据写到连续的内存空间中
格式:
ldm/stm Rm,{寄存器列表}
Rm寄存器中的数据将被看出内存的地址
寄存器中的寄存器如果连续就是用-隔开,如果不连续就用,隔开
寄存器列表中的寄存器要求从小到达的编号进行书写
栈的种类:
增栈:压栈之后栈指针向高地址移动
减栈:压栈之后栈指针向低地址移动
空栈:当前栈指针指向的空间没有有效的数据,可以先进性压栈,然后将栈指针移动到下一个空的位置
满栈:当前栈指针指向的空间由有效的数据,需要先移动栈指针指向一个没有有效数据的空间然后再压入数据之后此时栈指针指向的空间又有有效数据
栈的操作方式: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,=0x40000820
mov r0,#0x100
mov r1,#0x200
bl add_funcl
add r2,r0,r1 @r2 = r0 + r1 = 0x300
b stop
add_funcl:
stmfd sp!,{r0-r1} @压栈保存现场
mov r0,#0x300
mov r1,#0x400
add r3,r0,r1 @r3 = r0 + r1 = 0x700
ldmfd sp!,{r0-r1} @出栈恢复现场
mov pc,lr
stop: @stop标签
b stop @跳转指令,跳转到stop标签下的指令 类似goto
@裸机的程序中必须有一个死循环
.end @代码段结束
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
@方法2
mrs r0,cpsr
bic r0,r0,#0x1F
orr r0,r0,#0xD0
msr cpsr,r0
stop: @stop标签
b stop @跳转指令,跳转到stop标签下的指令 类似goto
@裸机的程序中必须有一个死循环
.end @代码段结束