2023/9/27 -- ARM

【汇编语言相关语法】

1.汇编语言的组成部分

1.伪操作:不参与程序的执行,但是用于告诉编译器程序该怎么编译
.text 
.global  .end   .if  .else  .endif  .data

2.汇编指令
编译器将一条汇编指令编译成一条机器码,在内存里一条指令占4字节内存,一条指令可以实现一个特定的功能

3.伪指令
不是指令,看起来像是一条指令,可以实现和指令类似的功能。一条伪指令实际上可能是由多条指令共同实现

4.注释
单行注释:   @
多行注释   /*  */
条件编译
     .if 0
       指令段
      .else
        指令段
      .endif

2.汇编指令的介绍

1.基本数据操作指令
    数据搬移指令   =
    数据移位指令   << >>  
    数据算数运算指令   + - * /
    位运算指令    &   | ~  ^
    数据比较指令
2.跳转指令
3.内存读写指令
4.状态寄存器读写指令
5.软中断指令

3.汇编指令的基本语法格式

    指令的基本格式:
<opcode>{<cond>}{s}  <Rd>,  <Rn>,  <shifter_operand>
    解释:
    
<opcode>:指令码
     {<cond>}:条件码
     {s}:状态位,如果在指令后面加上s,则运算的结果会影响CPSR的条件位
     <Rd>:目标寄存器
     <Rn>:第一操作寄存器  只能是寄存器
     <shifter_operand>:第二操作数,可以是寄存器,也可以是立即数
  按照指令码将第一操作寄存器和第二操作数进行运算,将运算后的结果保存在目标寄存器
  
注意:      
1.一条汇编指令一般占一行
2.汇编不区分大写小写                         

【汇编指令】

1.数据搬移指令

1.1 格式

<opcode>{<cond>}{s}  <Rd>,  <shifter_operand>
解释:
    
<opcode>:指令码
     {<cond>}:条件码
     {s}:状态位,如果在指令后面加上s,则运算的结果会影响CPSR的条件位
     <Rd>:目标寄存器
     <shifter_operand>:第一操作数,可以是寄存器,也可以是立即数
  按照指令码将第一操作数运算后的结果保存在目标寄存器
  
指令码功能:
    mov:将第一操作数的值保存在目标寄存器
    mvn:将第一操作数的值按位取反,将结果保存在目标寄存器

1.2 示例

1.3 立即数的概念

定义:能够直接当作指令的一部分参与到指令的执行过程中的数据就是立即数.立即数由一个0-255范围内的数循环右移偶数位获得。

在指令的32为中将低12位预留保存立即数的数据

如何判断一个数据是不是立即数:
  在0-255范围内找一个数,让它循环右移偶数位(一个0-15范围内的数*2得到),如果能够得到这个数据,则这个数就是一个立即数。
  循环右移:最低位移出去的数补到最高位
  0000 0000 0000 0000 0000 0000 0000 1010 
  右移两位: 0000 0000 0000 0000 0000 0000 0000 0010
  循环右移两位: 100000 0000 0000 0000 0000 0000 0000 10
  ex:
  0X104: 0000 0000 0000 0000 0000 0001 0000 0100
      循环右移2位-》000000 0000 0000 0000 000000 0100 0001   -》0x41
      换句话说,将0x41循环右移30位得到0X104,所以,0X104是一个立即数
0X101:0000 0000 0000 0000 0000 0001 0000 0001
0X101找不到一个0-255范围内的数循环右移得到它,所以0X101不是立即数

1.4 将非立即数保存至寄存器中

伪指令:
    LDR 目标寄存器,=数值
    将指定的数据放在目标寄存器中
    
ex:LDR r1,=0X12345678

2.移位指令

2.1 格式以及指令码

格式:<opcode>{<cond>}{s}  <Rd>,  <Rn>,  <shifter_operand>
解释:将第一操作寄存器的数值移位第二操作数指定的位数,将结果保存在目标寄存器中

指令码:
LSL:左移运算  低位补0
LSR:右移运算   高位补0
ROR:循环右移:低位移出的值补到高位

2.2 示例

1.左移
        mov r0,#0XFF
    lsl r1,r0,#0X4  @将R0的值左移4位保存在r1寄存器  R1结果:0XFF0
 2.右移
 mov r0,#0XFF
lsr r1,r0,#0X4  @将R0的值右移4位保存在r1寄存器  R1结果:0XF
3.循环右移
mov r0,#0XFF
ror r1,r0,#0X4  @将R0的值循环右移4位保存在r1寄存器  R1结果:0XF000000F
4.c风格写法
mov r0,#0XFF
ror r1,r0,#(0X1<<2)  @将R0的值循环右移4位保存在r1寄存器  R1结果:0XF000000F

3.位运算指令

3.1 格式以及功能码

格式:<opcode>{<cond>}{s}  <Rd>,  <Rn>,  <shifter_operand>
解释:将第一操作寄存器和第二操作数进行位运算,将结果保存在目标寄存器中

指令码:
    and:与 与0清0 与1不变
    orr:或  或1置1 或0不变
    eor:异或  相同为0 不同为1
    bic:按位清零指令,想将哪一位设置为0,只需要用bic指令给这一位运算一个1即可

3.2 示例

1.and:
mov r0,#0XFF
    and r1,r0,#0XF0  @R1结果为0XF0
 2.ORR:
     mov r0,#0XFF
    orr r1,r0,#0XF000  @R1结果为0XF0FF
3.EOR:
    ldr r0,=0xf0f0
    EOr r1,r0,#0XFF  @R1结果为0XF00F
0000 0000 0000 0000 0000 0000 1111 1111
0000 0000 0000 0000 1111 0000 1111 0000
结果:0000 0000 0000 0000 1111 0000 0000 1111 -》0XF00F

4.BIC
 ldr r0,=0xFF
    BIC r0,r0,#(0x1<<5)  @将R0的值第5位清0 @R0结果为0XDF

3.3 练习

LDR r1,=0X12345678  @将0X12345678存放在r1寄存器
0001 0010 0011 0100 0101 0110 0111 1000
1.将R1寄存器的第4位清0,其他位不变
        and r1,r1,#(~(0X1<<4))
    或者BIC R1,R1,#(0x1<<4)
2.将r1寄存器第7位置1,其他位不变
orr r1,r1,#(0X1<<7)
3.将r1寄存器[31:28]清0,其他位不变
and r1,r1,#(~(0Xf<<28))
    或者BIC R1,R1,#(0xF<<28)
4.将r1寄存器[7:4]置1,其他位不变
orr r1,r1,#(0XF<<4)
5.将r1寄存器[15:11]设置为10101,其他位不变 
    @先清0
    BIC R1,R1,#(0X1F<<11)
    @再置位
    orr r1,r1,#(0X15<<11)

4.算数运算指令

4.1 格式以及指令码

格式:<opcode>{<cond>}{s}  <Rd>,  <Rn>,  <shifter_operand>
解释:将第一操作寄存器的值和第二操作数进行算数运算,结果保存在目标寄存器中

add:加法运算
adc:进行加法运算时需要考虑CPSR的条件位
sub:减法运算
sbc:进行减法运算时需要考虑CPSR的条件位
mul:乘法运算

4.2 示例

1.ADD:加法
  ex1:  mov r1,#1
      mov r2,#2
     add r3,r1,r2@r3=r1+r2
  ex:
      mov r1,#0XFFFFFFFE
    mov r2,#2
    addS r3,r1,r2@r3=r1+r2  @运算的结果影响到条件位
2.SUB
        mov r1,#0XFFFFFFFE
    mov r2,#2
    sub r3,r1,r2@r3=r1-r2
 ex2:
         mov r1,#0XFFFFFFFE
    mov r2,#2
    subs r3,r2,r1@r3=r2-r1 
3.ADC
mov r1,#0XFFFFFFFE
mov r2,#2
    ADDS r3,r2,r1 @r3=r1+r2 
    ADC R4,R2,#3  @R4=R2+3+cpsr(C位)  6 
 
4.sbc:减法运算考虑条件位
mov r1,#0XFFFFFFFE
    mov r2,#2
      SUBS r3,r2,r1 @r3=R2-R1    4
    sbC R4,R1,#3  @R4=R1-3-CPSR(C位取反)

4.3 64位数据进行算数运算

原则:
一个 64位数保存在两个寄存器
高32位运算,低32位运算
     mov r1,#0XFFFFFFFE  @保存第一个数据的低32位
    mov r2,#2@保存第一个数据的高32位
    mov r3,#3 @保存第二个数据的低32位
    mov r4,#4 @保存第2数据的高32位
    @低32位运算要求影响条件位
    ADDS R5,R1,R3@R5保存运算后结果的低32位
    ADC R6,R2,R4@R6寄存器保存运算结果的高32位,需要考虑条件位
    

5.比较指令

格式:
    cmp 第一操作数,第二操作寄存器
    比较两个数据
cmp命令本质:实际上就是比较的两个数进行减法运算,并且减法运算的结果会影响到CPSR寄存器的条件位
通常比较指令完毕之后会使用条件码进行判断,根据判断的结果做不同的逻辑
    

条件码

在一个指令后面加上条件码的助记词后缀,如果满足条件码对应的条件,我们就会进行对应的指令操作,否则不进行操作

mov r1,#3
        mov r2,#4
        cmp r1,r2  @比较两个数
        SUBHI r3,r1,r2  @如果r1>r2 进行减法运算
        MULEQ r3,r1,r2@如果两数相等,进行乘法运算
        ADDCC R3,R1,R2@如果r1<r2  ,进行加法运算

6. 跳转指令

格式:
<opcode>{<cond>} 标签
功能:跳转到指定的标签下

指令码:
b:跳转时不影响LR寄存器的值

ex:.text
.global  _start
    
_start:
        mov r1,#3
        mov r2,#4
        b fun1 @程序跳转
        mul r5,r1,r2
    
stop:
    b stop  

fun1:
    add r4,r1,r2

    
    
.end
    

bl:跳转时影响LR寄存器的值

.text
.global  _start
    
_start:
        mov r1,#3
        mov r2,#4
        bl fun1 @程序跳转
        mul r5,r1,r2
    
stop:
    b stop  

fun1:
    add r4,r1,r2
    mov pc,lr @程序返回

    
    
.end
    

【任务】

实现1-100的累加

.text
.globl _start

_start:  
	MOV R0,#0
	MOV R1,#1
	MOV R2,#100
	
FUN:	
	CMP R1,R2
	ADDNE R0,R0,R1
	ADDNE R1,R1,#1
	BNE FUN		
	
stop:
	b stop
.end
	

猜你喜欢

转载自blog.csdn.net/weixin_54147737/article/details/133362201