Linux 学习记录52(ARM篇)

Linux 学习记录52(ARM篇)

本文目录

  • Linux 学习记录52(ARM篇)
  • 一、汇编语言相关语法
    • 1. 汇编语言的组成部分
    • 2. 汇编指令的类型
    • 3. 汇编指令的使用格式
  • 二、基本数据处理指令
    • 1. 数据搬移指令
      • (1. 格式
      • (2. 指令码类型
      • (3. 使用示例
    • 2. 立即数
      • (1. 一条指令的组成
    • 3. 移位操作指令
      • (1. 格式
      • (2. 指令码类型
      • (3. 使用示例
    • 4. 位运算指令
      • (1. 格式
      • (2. 指令码
      • (3. 运算规则
      • (4. 使用示例
      • (5. 练习
    • 5. 算数运算指令
      • (1. 格式
      • (2. 指令码
      • (3. 使用示例
      • (4. 关于32位的处理器进行64位数据的运算原理
    • 6. 比较指令
      • (1. 概述
      • (2. 比较指令结果的条件码
      • (3. 使用示例
    • 7. 跳转指令
      • (1. 概述
      • (2. 不保存返回地址
      • (3. 跳转之前保存返回地址
  • 练习
    • 1. 实现1-100的累加

一、汇编语言相关语法

1. 汇编语言的组成部分

1.伪操作
    不参与到程序的执行,但是可以告诉编译器程序应该怎么执行,或者程序中每一个部分有什么含义
    .text .global  .globl .end  .if .else .endif   
2.汇编指令
    编译器将一条汇编指令编译成一条机器码,执行指令后可以让ALU做出对应的运算操作,实现特定的功能
3.伪指令
    不是汇编指令,但是可以起到和汇编指令一样的作用,通常一条伪指令的实现需要多条汇编指令一起完成
    
4.汇编里的注释:
    单行注释:使用@  其他架构下的汇编单行注释 可能会使用';'
    多行注释:/**/
    条件注释:根据if后面的数值真假来去执行不同的指令段,如果为真,执行指令段1,否则执行指令段2
        .if 数值
            指令段1
        .else
            指令段2
        .endif                

2. 汇编指令的类型

  1. 基本的数据处理指令
  1. 数据搬移指令
  2. 数据移位指令
  3. 算数运算指令
  4. 位运算指令
  5. 比较指令
  1. 跳转指令
  2. 内存读写指令
  3. 程序状态寄存器读写指令
  4. 软中断指令

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 

Linux 学习记录52(ARM篇)_第1张图片
Linux 学习记录52(ARM篇)_第2张图片

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指令进行判断
Linux 学习记录52(ARM篇)_第3张图片

可以使用伪指令
Linux 学习记录52(ARM篇)_第4张图片

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  

Linux 学习记录52(ARM篇)_第5张图片

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. 运算规则

Linux 学习记录52(ARM篇)_第6张图片

(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  

Linux 学习记录52(ARM篇)_第7张图片

(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  

Linux 学习记录52(ARM篇)_第8张图片

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  

Linux 学习记录52(ARM篇)_第9张图片

(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

Linux 学习记录52(ARM篇)_第10张图片

练习

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  

Linux 学习记录52(ARM篇)_第11张图片

你可能感兴趣的:(Linux学习记录,linux,学习,arm开发)