zoukankan      html  css  js  c++  java
  • ARM常用指令+源码解读

    概念阐述:

    AREA

    段名 属性1,属性2

    — CODE 属性:用于定义代码段,默认为READONLY 。

    — DATA 属性:用于定义数据段,默认为READWRITE 。

    — READONLY 属性:指定本段为只读,代码段默认为READONLY 。

    — READWRITE 属性:指定本段为可读可写,数据段的默认属性为READWRITE 。

    — ALIGN 属性:使用方式为ALIGN表达式。在默认时,ELF(可执行连接文件)的代码段和数据段是按字对齐的,表达式的取值范围为0~31,相应的对齐方式为2表达式次方。

    — COMMON 属性:该属性定义一个通用的段,不包含任何的用户代码和数据。各源文件中同名的COMMON段共享同一段存储单元

    ENTRY

    ENTRY伪指令用于指定汇编程序的入口点。在一个完整的汇编程序中至少要有一个ENTRY(也可以有多个,当有多个ENTRY时,程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个ENTRY(可以没有)。

    IMPORT

    标识符表明要调用的函数为本模块外部定义的

    EXPORT

    标识符表示本模块中定时的符号可以为外部模块使用

    EQU

    EQU 指令用于将一个数值或寄存器名赋给一个指定的符号名。

    用法:①符号名 EQU 表达式

    ​ ②符号名 EQU 寄存器名

    MOV

    将源操作数source的值复制到target中去,source值不变

    用法:MOV target,source

    ADD

    将后面的操作数加到前面操作数中

    用法:ADD reg/mem reg/mem/imm

    SUB

    将前面的数减去后面的数,存到前面的寄存器中

    用法:SUB reg/mem reg/mem/imm

    LDR(指令

    与MOV功能类似,相当于立即数没有超过8位执行的MOV指令,使用时没有等号

    例1: ldr r0, 0x12345678 // 就是把0x12345678这个地址中的值存放到r0中。而mov不能干这个活,mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中。
    例2:ldr r0,r1 //表示把r1寄存器中的值放入r0
    例3:ldr r0,[r1] // [r1]表示r1中值对应内存的地址,所以是把r1中的数当作一个地址,把这个地址中的值放入r0

    LDR(伪指令

    与MOV功能类似,相当于立即数没有超过8位执行的MOV指令,使用时有等号

    例1(立即数):LDR r0, =0x12345678 //把0x12345678这个地址写到r0中

    例2(标号): LDR r0, =_start //将指定标号的地址赋给r0

    DCD

    数据定义( Data Definition )伪指令

    一般用于为特定的数据分配存储单元,同时可完成已分配存储单元的初始化。

    用法:标号 DCD(或 DCDU) 表达式

    CMP

    (比较)指令执行从目的操作数中减去源操作数的隐含减法操作

    用法:CMP destination,source

    如果比较的是两个无符号数,则零标志位和进位标志位表示的两个操作数之间的关系如右表所示:

    CMP结果 ZF CF
    目的操作数 < 源操作数 0 1
    目的操作数 > 源操作数 0 0
    目的操作数 = 源操作数 1 0

    如果比较的是两个有符号数,则符号标志位、零标志位和溢出标志位表示的两个操作数之间的关系如右表所示:

    CMP结果 标志位
    目的操作数 < 源操作数 SF ≠ OF
    目的操作数 > 源操作数 SF=OF
    目的操作数 = 源操作数 ZF=1

    例1:

    MOV ax, 5
    CMP ax,10 ; ZF = 0 and CF = 1

    例2:

    MOV ax,1000
    MOV cx,1000
    CMP cx, ax ;ZF = 1 and CF = 0

    例3:

    MOV si,105
    CMP si, 0 ; ZF = 0 and CF = 0

    B,BL

    跳转。BL相当于C中的调用子函数,在跳转的标号最后加上MOV PC,LR 就可以返回BL下一条指令。

    BGE

    GE是指令条件,意思就是greater or equal,大于或等于,似乎几乎zd可以加到所有指令上。
    BGE中的B是回branch,跳转的意思,BGE就是大答于或等于才跳。

    BEQ

    BEQ(比较相等,EQ为相等) 在BEQ指令前应该有一条比较指令,比如CMP R0,R1 若R0=R1,则执行BEQ指令,否则不执行。

    BNE

    BNE: 数据跳转指令,标志寄存器中Z标志位不等于零时, 跳转到BNE后标签处。

    与b的区别:BNE指令,是个条件跳转,即:是“不相等(或不为0)跳转指令”。如果不为0就跳转到后面指定的地址,继续执行。

    B 是最简单的分支。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的地址,从那里继续执行。

    与BGE的区别:BNE指令会去查看状态寄存器,当Z!=1的时候就跳转到指定位置,BEQ功能与BNE刚好相反,Z==1的时候才跳转到指定位置.

    BX

    跳转并切换指令集。

    bx lr的作用等同于mov pc,lr

    可以使用MOV PC, LR或者BX LR来完成子程序返回。另外,也可以在在子程序入口处使用下面的指令将LR保存到栈中

    LR

    链接寄存器(用来存放子程序的返回地址) LR相当于指针变量,指令在内存中的地址。如果子程序再调用子程序,返前一次调用的子程序的返回地址要存储栈内 。

    N 当用两个补码表示的带符号数进行运算时,N=1表示运算的结果为负数;N=0表示运算的结果为正数或零.
    Z Z=1表示运算的结果为零,Z=0表示运算的结果非零。
    C 可以有4种方法设置C的值:
    加法运算(包括CMN):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。
    减法运算(包括CMP):当运算时产生了借位时(无符号数溢出),C=0,否则C=1。
    对于包含移位操作的非加/减运算指令,C为移出值的最后一位。
    对于其它的非加/减运算指令,C的值通常不会改变。
    V 可以有2种方法设置V的值:
    对于加减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出
    对于其它的非加/减运算指令,V的值通常不会改变。

    DCD

    用于分配一片连续的字存储单元并用指定的数据初始化。

    明白了一些概念咋们来实战吧~

    源码解读:

    该程序实现了什么功能呢~?

    ;routine for find max value in a integer array.
    ;R1 is the counter of the loop.
    ;R2 is the pointer of the arraye element. R3 is the value of array element pointed by R2.
    ;R4 is alway pointing to the max element finded up now,and R5 is the value of the array element pointed by R4.
    ;在整数数组中查找最大值的例程。
    ;R1是循环的计数器。
    ;R2是arraye元素的指针。R3是R2指向的数组元素的值。
    ;R4总是指向现在找到的max元素,R5是R4指向的数组元素的值。
    N EQU 10	;讲N的值定义为10
        AREA findEX01,CODE,READONLY 
        ;这是段名为findEX01(findEX01),可读可写(READONLY)的代码段(CODE)
        ENTRY	;程序开始
        EXPORT findnum	;findnum代码块可以在外部模块使用
    findnum		;函数名,该函数用于初始化寄存器R1~R5的值
        MOV R1,#N-1		;将N-1的值存放到寄存器R1中
        LDR R2,=finddata10		;将finddata10的首地址存到R2中
        LDR R3,[R2]		;将R2中的值作为地址,从该地址取出数据存到R3中,finddata10第一个元素的值为0x70,R3将存储0x70
        MOV R4,R2		;将R2的值存放到R4中
        MOV R5,R3		;将R3的值存放到R5中,这两步是为了从首地址开始遍历嘛
    findloop02		;函数名,该函数内前半部分用于R2指针遍历数组中的连续单元,中间部分用于比较找出最大值,如果R2指向的值比R5大,将该值的地址存在R4中,该值存在R5中。
        ADD R2,R2,#4	;将R2中的值与4相加存到R2中:储存一个数需要4字节,因此指向下一个数需要偏移4个字节
        LDR R3,[R2]		;将R2的值作为地址,从该地址取出数据存到R3中
        CMP R5,R3		;比较R5和R3的值
        BGE findskip	;当R5>R3时跳到findskip函数,R5<=R3时继续执行
        MOV R4,R2		;将R2的值存到R4中
        MOV R5,R3		;将R3的值存到R5中
    findskip		;函数名,用作循环,类似于for(i=9;i>=0;i--)
        SUB R1,R1,#1	;R1自减
        CMP R1,#0		;将R1的值与R0比较
        BNE findloop02	;当R1!=0时,跳转到findloop02函数
        
        BX LR			;等同于 MOV pc,lr, 这里是完成子程序的返回
        
        AREA finddat0,DATA,READWRITE
        ;这是段名为finddat0(finddat0),可读可写(READONLY)的数据段(DATA)
    finddata10 DCD 0x70,0x30,0x20,0x80,0x35,0x65,0x55,0x75,0x25,0x60
    ;分配一段连续的单元地址
    	END				;结束模块
    

    所以!它就是开了个数组,找到了数组中的最大元素!写了一晚上,甚至激动QAQ比前一篇文章好一些了,一丢丢基础都没花时间理清关系挺艰辛的qaq碎觉觉了

  • 相关阅读:
    通用分页后台显示
    自定义的JSP标签
    Java反射机制
    Java虚拟机栈---本地方法栈
    XML建模实列
    XML解析与xml和Map集合的互转
    [离散数学]第二次作业
    [线性代数]2016.10.13作业
    [数字逻辑]第二次作业
    [线性代数]2016.9.26作业
  • 原文地址:https://www.cnblogs.com/lightice/p/12657316.html
Copyright © 2011-2022 走看看