Linux 学习记录52(ARM篇)
一、汇编语言相关语法
1. 汇编语言的组成部分
1.伪操作
不参与到程序的执行,但是可以告诉编译器程序应该怎么执行,或者程序中每一个部分有什么含义
.text .global .globl .end .if .else .endif
2.汇编指令
编译器将一条汇编指令编译成一条机器码,执行指令后可以让ALU做出对应的运算操作,实现特定的功能
3.伪指令
不是汇编指令,但是可以起到和汇编指令一样的作用,通常一条伪指令的实现需要多条汇编指令一起完成
4.汇编里的注释:
单行注释:使用@ 其他架构下的汇编单行注释 可能会使用';'
多行注释:/**/
条件注释:根据if后面的数值真假来去执行不同的指令段,如果为真,执行指令段1,否则执行指令段2
.if 数值
指令段1
.else
指令段2
.endif
2. 汇编指令的类型
- 基本的数据处理指令
- 数据搬移指令
- 数据移位指令
- 算数运算指令
- 位运算指令
- 比较指令
- 跳转指令
- 内存读写指令
- 程序状态寄存器读写指令
- 软中断指令
3. 汇编指令的使用格式
格式:opcode{cond}{s} Rd, Rn, shifter_operand
解释:
opcode : 指令码
cond : 条件码
默认汇编指令是无条件执行的,使用条件码之后可以让汇编有条件的执行
s: 状态位
指令的执行结果会影响cpsr的NZCV位
Rd : 目标寄存器
运行的结果放到目标寄存器
Rn : 第一个操作寄存器,只能是一个寄存器
shifter_operand : 第二个操作数
1> 可以是一个普通的寄存器
2> 可以是一个立即数
3> 可以是经过移位操作的寄存器
opcode{cond}{s} : 连到一起写
Rd, Rn, shifter_operand : 使用逗号隔开
opcode{cond}{s}和Rd, Rn, shifter_operand直接使用空格隔开
一条汇编指令占一行;
汇编代码中不严格区分大小写:
二、基本数据处理指令
1. 数据搬移指令
(1. 格式
opcode{cond}{s} Rd, shifter_operand
指令码 目标寄存器 操作数
(2. 指令码类型
1. mov:将操作数搬移到寄存器中
2. mvn:将操作数按位取反后搬移到目标寄存器中
(3. 使用示例
.text
.global _start
_start:
mov r0,#0XFF @将0XFF搬移到r0寄存器中
mvn r1,#0XFF @将0XFF按位取反结果存放到R1寄存器中
stop:
b stop
.end
2. 立即数
能够当作指令的一部分去执行的数据叫做立即数。一个立即数可以通过一个0-255之间的数字进行循环右移得到
如何判断一个数据是不是立即数:
在0-255内找到一个数据,将数据循环右移偶数位,如果能够得到这个数据,就说明这个数据是一个立即数
ex1:0X104->二进制:0000 0000 0000 0000 0000 0001 0000 0100
找到一个0-255范围内的数:0000 0000 0000 0000 0000 0000 0100 0001——》0X41
0x41循环右移30位可以得到0X104,所以0X104就是立即数
ex:0X101->二进制:0000 0000 0000 0000 0000 0001 0000 0001
(1. 一条指令的组成
在32位下一条指令大小为32字节
[0:7] "0-255的数据 进行循环右移的数据,通过这个数据循环右移偶数位可以得到第二操作数"
[8:11] "低八位循环右移的偶数位对应拖偶数由这个区间的数值*2得到"
[12:15] "Rd 目标寄存器标识"
[16:19] "Rn 操作寄存器标识"
[20:21] "s 状态位"
[22:25] "opcond 指令码"
[26:27] "001"
[28:31] "cond 条件码"
注意:对于立即数的判断,如果数据mov指令的操作数>0XFFFF0000,则在计算机处理时,按照MVN指令进行判断
可以使用伪指令
3. 移位操作指令
(1. 格式
格式:opcode{cond}{s} Rd, Rn, shifter_operand
解释:
opcode : 指令码
cond : 条件码
默认汇编指令是无条件执行的,使用条件码之后可以让汇编有条件的执行
s: 状态位
指令的执行结果会影响cpsr的NZCV位
Rd : 目标寄存器
运行的结果放到目标寄存器
Rn : 第一个操作寄存器,只能是一个寄存器
shifter_operand : 第二个操作数
(2. 指令码类型
1. 左移运算 低位补0
2. lsr:右移运算 高位补0
3. ror:循环右移 低位移出的数据补到最高位
(3. 使用示例
.text
.global _start
_start:
mov r0,#0XFF
lsl r1,r0,#4 @ 将r0的值左移4位结果放到r1中 R1==0XFF0
lsr r2,r0,#4 @将r0的值右移4位结果放到r2中 R2==0XF
ror r3,r0,#4 @ 将r0的值循环右移4位结果放到r3中 R3==0XF000000F
stop:
b stop
.end
4. 位运算指令
(1. 格式
格式:opcode{cond}{s} Rd, Rn, shifter_operand
解释:
opcode : 指令码
cond : 条件码
默认汇编指令是无条件执行的,使用条件码之后可以让汇编有条件的执行
s: 状态位
指令的执行结果会影响cpsr的NZCV位
Rd : 目标寄存器
运行的结果放到目标寄存器
Rn : 第一个操作寄存器,只能是一个寄存器
shifter_operand : 第二个操作数
(2. 指令码
1. and:按位与 与0清0,与1不变
2. orr:按位或 或1置1 或0不变
3. eor:按位异或 相同为0 不同为1
4. bic:按位清0 想要哪一位设置为0,只需要将这一位用bic指令和相同位为1的数进行运算
(3. 运算规则
(4. 使用示例
.text
.global _start
_start:
mov r0,#0XFF
and r1, r0,#0XF @r1==0XF
orr r2,r0,#0XF00 @r2==0XFFF
eor r3,r0,#0XF @R3==0XF0
bic r4,r0,#0X14 @R4==0XEB
stop:
b stop
.end
(5. 练习
LDR r0,=0X12345678
0001 0010 0011 0100 0101 0110 0111 1000
1.将r0寄存器的第4位清0,其他位不变
bic r0,r0,#(1<<4)
或者
and r0,r0,#(~(1<<4))
2.将R0寄存器的第7位置1,其他位不变
orr r0,r0,#(1<<7)
3.将r0寄存器的第[31:28]清0,其他位不变
bic r0,r0,#(0XF<<28)
4.将r0寄存器第[7:4]位置1,其他位不变
ORR r0,r0,#(0XF<<4)
5.将R0寄存器的第[15:11]位设置为10101,其他位不变
思路:把指定的几位设置为特定的数值,先把这几位清0,在赋值
BIC r0,r0,#(0X1F<<11)@先清0
ORR r0,r0,#(0X15<<11)@再赋值
5. 算数运算指令
(1. 格式
格式:opcode{cond}{s} Rd, Rn, shifter_operand
解释:
opcode : 指令码
cond : 条件码
默认汇编指令是无条件执行的,使用条件码之后可以让汇编有条件的执行
s: 状态位
指令的执行结果会影响cpsr的NZCV位
Rd : 目标寄存器
运行的结果放到目标寄存器
Rn : 第一个操作寄存器,只能是一个寄存器
shifter_operand : 第二个操作数
(2. 指令码
1. add :进行加法运算
2. adc:进行加法运算的时候考虑到CPSR的c位
3. sub:进行减法运算
4. sbc:进行减法运算时考虑到CPSR的C位
5. mul:乘法运算
(3. 使用示例
1.加法1:
MOV r0,#1
mov r1,#3
add r2,r0,r1 @将r0+r1的结果存放r2寄存器
2.加法2:
MOV r0,#0XFFFFFFFE
mov r1,#3
adds r2,r0,r1 @将r0+r1的结果存放r2寄存器,+s结果进位就会影响到CPSR的c位
3.减法运算
MOV r0,#3
mov r1,#0XFFFFFFFE
subs r2,r0,r1 @将r0-r1的结果存放r2寄存器
(4. 关于32位的处理器进行64位数据的运算原理
原理:一个64位的数据放在两个寄存器中,分别存放这个数据的高64位以及低64位
进行64位数据运算时,将两个64位数据的低32位运算,高32位运算
以加法为例子:
MOV r0,#0X3 @第一个64位数的低32位
mov r1,#0X1 @第一个数的高32位
mov r2,#0XFFFFFFFE @第2个64位数的低32位
mov r3,#0X4 @第二个64位数据的高32位
adds r4,r0,r2 @两个低32位数运算,结果影响到CPSR的C位
adc r5,r1,r3 @两个高32位数据运算,结果存放在r5中,考虑到C位
6. 比较指令
(1. 概述
格式:
opcode Rn, shifter_operand
opcode:比较指令的指令码是cmp
功能:将第一操作寄存器和第二操作数的值进行比较
本质:比较指令的本质就是拿进行比较的两个数值进行减法运算,并且减法运算的结果会影响到CPSR的条件位
我们可以根据条件位的数值进行两个数值的判断,再根据判断的结果做不同的操作
一般比较指令和条件码都是一起使用的
(2. 比较指令结果的条件码
条件码 | 助记符后缀 | 标志 | 含义 |
---|---|---|---|
0000 | eq | z置位 | 相等 |
0001 | ne | z清零 | 不相等 |
0010 | cs | c置位 | 无符号数大于或等于 |
0011 | cc | c清零 | 无符号数小于 |
0100 | mi | n置位 | 负数 |
0101 | pl | n清零 | 正数或零 |
0110 | vs | v置位 | 溢出 |
0111 | vc | v清零 | 未溢出 |
1000 | hi | c置位z清零 | 无符号数大于 |
1001 | ls | c清零z置位 | 无符号数小于或等于 |
1010 | ge | n等于v | 带符号数大于或等于 |
1011 | lt | n不等于v | 带符号数小于 |
1100 | gt | z清零且n等于v | 带符号数大于 |
1101 | le | z置位或n不等于v | 带符号数小于或等于 |
1110 | al | 忽略 | 无条件执行 |
(3. 使用示例
.text
.global _start
_start:
MOV r0,#0X3
mov r1,#0X1
cmp r0,r1 @数值比较
@根据比较的结果执行不同的指令
addeq r2,r1,r0 @如果两个数相等,两数相加,将结果保存至r2中
subcs r3,r0,r1 @如果r0>=r1,就做减法运算,将结果保存在r3寄存器
mulcc r4,r0,r1 @如果r0<r1,就做乘法运算,结果保存在r4寄存器中
stop:
b stop
.end
7. 跳转指令
(1. 概述
格式:
opcode{cond} label
功能:跳转到指定的标签下
功能码:
1. b :跳转到指定的标签下,返回地址不保存
2.bl:跳转到指定的标签下,返回地址保存至 LR寄存器中
(2. 不保存返回地址
.text
.global _start
_start:
MOV r0,#0X3
mov r1,#0X1
b fun @跳转到fun标签
cmp r0,r1 @数值比较
@根据比较的结果执行不同的指令
addeq r2,r1,r0 @如果两个数相等,两数相加,将结果保存至r2中
subcs r3,r0,r1 @如果r0>=r1,就做减法运算,将结果保存在r3寄存器
mulcc r4,r0,r1 @如果r0<r1,就做乘法运算,结果保存在r4寄存器中
fun:
mov r3,#3
mov r4,#4
stop:
b stop
.end
(3. 跳转之前保存返回地址
.text
.global _start
_start:
MOV r0,#0X3
mov r1,#0X1
bl fun @跳转到fun标签,返回地址保存至LR寄存器
cmp r0,r1 @数值比较
@根据比较的结果执行不同的指令
addeq r2,r1,r0 @如果两个数相等,两数相加,将结果保存至r2中
subcs r3,r0,r1 @如果r0>=r1,就做减法运算,将结果保存在r3寄存器
mulcc r4,r0,r1 @如果r0<r1,就做乘法运算,结果保存在r4寄存器中
fun:
mov r3,#3
mov r4,#4
mov pc,lr @程序返回
stop:
b stop
.end
文章来源:https://www.toymoban.com/news/detail-580792.html
练习
1. 实现1-100的累加
.text
.global _start
_start:
mov r0,#0 @将r0作为计数器
mov r1,#0 @将r1作为和
stop:
add r0,#1 @累计循环次数
cmp r0,#101 @比较循环次数
beq over @当满足条件时跳转至over处
addls r1,r1,r0 @当循环次数小于101时累加
b stop
over: @当循环结束跳转到次处
mov r2,r1 @将r1计算的结果赋值给r2
.end
文章来源地址https://www.toymoban.com/news/detail-580792.html
到了这里,关于Linux 学习记录52(ARM篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!