ARM的指令集

    xiaoxiao2021-03-25  135

    一个汇编文件中包含以下部分:

    1, 汇编指令, 被编译成一条一条的汇编指令存放在内存中,

    2, 伪指令,在编译的时候会被编译器替换成多条可以识别的arm汇编指令

    3, 伪操作,引导编译器进行相关的编译工作,不会被编译成汇编指令,也不占内存空间

    4, 标号,起标识某一个地址的作用,不占内存空间

     

     

    汇编指令:

    1. 数据处理指令    --  对数据进行算术运算或者逻辑运算或者其他处理方法

    2. 跳转指令  --  可以实现程序的跳转

    3. load/store架构指令  --  对处理器的内存进行操作的指令

    4. PSR数据传送指令     --  用来操作程序状态寄存器

    5. 协处理器指令        --  用来操作协处理器

    6. 软中断指令          --  用来触发一个软中断异常

     

    1】数据处理指令

    语法:

    <指令>{<cond>}{S} Rd, Rn, Operand2

    <指令>:指令的名字

    {<cond>}:条件码  如果本指令加了条件码,必须条件满足这条指令才会执行, 不加条件码表示无条件执行

    {S}:状态标记,只有当前指令加了S,那么运算结果才会影响CPSR寄存器的条件位

     Rd:目的寄存器(比较指令没有目的寄存器)

    Rn:第一操作寄存器(数据搬移指令没有第一操作寄存器)

    Operand2:第二操作数(立即数,前面加#标识,16进制或者10进制),如果是寄存器的话,称之为第二操作寄存器

     

     

    .text                      @指定一个代码段

    .global _start             @把_start标号定义成全局的

    _start:                        @定义一个标号_start, 是汇编程序的默认入口

     

    mov r0, #0xff              @汇编指令,将0xff这个数据搬移到r0寄存器中

    stop:                          @标号

    b stop                     @跳转指令,相当于while(1), 防止程序跑飞

    .end                       @伪操作,表示汇编程序的结束

     

    1】数据搬移: MOV  MVN

    mov r0, #0xff      @r0 = 0xff

    mvn r1, #0xff      @r1 = ~0xff

    mov r2, r1         @r2 = r1

     

    2】算术指令: ADD ADC SUB SBC RSB RSC

    mov r0, #4

    add r1, r0, #1         @r1 = r0 + 1   

    add r2, r1, r0         @r2 = r1 + r0

    add r2, #1             @r2 = r2 + 1

    @add r3, r0, #0xffffffff    不会改变C位

    adds r3, r0, #0xffffffff    @C = 1   N = 0  Z = 0

    adc r4, r0, #1              @带进位的加法指令 r4 = r0 + 1 + C

    @两个64位的数据进行加法运算,第一个64位数据的高32位放在r0中,低32位放在r1中,另一个数的高32位放在r2中,低32位放在r3中

    mov r0, #0x1

    mov r1, #0xffffffff

    mov r2, #0x4

    mov r3, #0x5

    adds r4, r1, r3        @产生进位  C = 1

    adc r5, r0, r2         @r5 = r0 + r2 + C

     

     

    mov r0, #4

    sub r1, r0, #1           @r1 = r0 - 1

    sub r2, r0, r1           @r2 = r0 - r1

    sub r0, #1               @r0 = r0 - 1

    subs r4, r0, #5          @N = 1  C = 0  Z = 0

    sbc r0, #1               @带借位的减法,r0 = r0 - 1 - !C

     

     

    32位乘法

    MUL{<cond>}{S}    R0, R1, R2                    R0 = R1 * R2

    MLA{<cond>}{S}    R0,R1,R2,R3                            R0 = (R1 * R2) + R3    乘加指令

     

    mul r4, r0, r1       @r4 = r0 * r1

    @mul r4, r0, #4      报错,乘法指令不能使用操作数

    mla  r5, r0, r1, r3  @r5 = r0 * r1 + r3

     

    2】比较指令  cmp

    mov r0, #4

    mov r1, #5

    cmp r0, #4      @cmp指令本质进行的是减法指令,没有目的寄存器   r0 - 4 = 0  Z = 1  C = 1

     

    注意:所有的指令只有比较指令不加S,运算结果会影响CPSR寄存器,其他指令必须加S才会影响

     

     

    3】逻辑指令: AND  ORR EOR BIC

    mov r0, #0xff

    and r1, r0, #0xfffffff0       @r1 = r0 & 0xfffffff0

    orr r2, r0, #0xf00            @r2 = r0 | 0xf00

    eor r3, r0, #0xf              @r3 = r0 ^ 0xf (取反)

    bic r4, r0, #0xf              @位清零指令   哪些位为1就将哪些位清零   r4 = r0 & (~(0xf))

    bic r5, r0, #0x50             @第4位和第6位清零

     

     

    4】跳转指令(分支指令)

    Branch : B{<cond>} label

    Branch with Link : BL{<cond>} subroutine_label     //带返回的跳转,本质会保存返回地址

     

    跳转范围:± 32 Mbyte

    如何执行长跳转?  mov pc, #0xffffff

              ldr pc, =lable

     

    需求:将r0和r1中的数求和  然后求差, 最后相加

    _start:

     

    mov r0, #5

    mov r1, #3

    bl ad

    bl sb

    add r4, r2, r3

    stop:

    b stop

     

    ad:

    add r2, r1, r0

    mov pc, lr

    sb:

    sub r3, r0, r1

    mov pc, lr

     

    5】条件码

    EQ: 相等     Z = 1

    NE: 不相等   Z = 0

    GT: 大于     N = 0 且 Z = 0

    GE: 大于等于 N = 0

     

    LT: 小于     N = 1

    LE: 小于等于 N = 1 或 Z = 1

     

     

    mov r0, #4

    mov r1, #3

    cmp r0, r1

    bleq stop

    addgt r3, r0, r1

     

     

    指令练习:

    if (a==0) func(1);

     

    cmp r0, #0

    mov r0, #1    //传递参数

    bleq func

     

     

            if (a==0) x=0;

    if (a>0)  x=1;

    cmp r0, #0

    moveq r1, #0

    movgt r1, #1

     

     

    if (a==4 || a==10) x=0;

     

    cmp r0, #4

    cmpne r0, #10

    moveq r1, #0

     

     

    6】桶型移位器

    LSL:  逻辑左移   高位丢弃,低位补0

    LSR:  逻辑右移   低位丢弃,高位补0

    ASR:  算术右移   低位丢弃,高位补符号位   如果移动多个位,高位全部补符号位

    ROR:  循环右移   低位补高位

     

     

    mov r0, #1

    mov r1, r0, lsl #1       @r1 = r0 << 1

    add r1, r0, lsl #1       @r1 = r1 + (r0 << 1)

    mov r0, #0xf

    mov r1, r0, ror #4

    mov r0, #0xf0000000

    mov r1, r0, asr #4

     

    7】立即数和有效数

    立即数:如果一个数可以通过一个8位的数(0-255)ROR偶数位得到,那么这个数就是一个立即数

    如何判断一个数是否是立即数:

    1. 展开成二进制,如果1的个数大于8,肯定不是一个立即数

     

    0x3fc00000     是一个立即数

    0011 1111 1100  ...

     

    0x1fe00000     不是一个立即数

    0001 1111 1110 0000 ...

     

    0x3e800000     是

    0011 1110 1000 ....

    0x30100000     不是

    0011 0000 0001 0000 ....

     

    有效数:

    如果一个数是立即数,那么这个数也是有效数

    如果一个数安位取反之后得到的数是立即数,那么这个数就是有效数

     

     

    ldr r0, =0x12345678    //ldr伪指令,将任意数据搬移到一个通用寄存器中

     

     

    GCD练习:

    mov r0, #9

    mov r1, #15

    loop:

    cmp r0, r1

    beq stop

    subgt r0, r1

    sublt r1, r0

    b loop

     

    load/store架构指令

    1. 单寄存器指令

    2. 多寄存器指令

    3. 数据交换指令

     

     

    1. 单寄存器指令

    语法:

      LDR{<cond>}{<size>} Rd, <address>        //内存 ==> 寄存器

    STR{<cond>}{<size>} Rd, <address>        //寄存器 ==> 内存

    {<size>}: B  H  不写(W)

    Rd:目的寄存器

    <address>:地址有三种形式

    1) 标号

    ldr r0, lable

    2)寄存器间接寻址

    str r0, [r1]

    3)基址变址寻址

       a. 前索引

    str r0, [r1, #4]

       b. 自动索引

    str r0, [r1, #4]!

       c. 后索引

    str r0, [r1], #4

     

     

     

     

     

    =============     标号    =============================

    ldr r1, label    @将label这个标号下面的数据读取到r1寄存器中

    ldrb r2, label

    stop:

    b stop

     

    label:

    .word 0x12345678

     

    =================  寄存器间接寻址  ====================

    mov r0, #0x41000000      @0x40000000,0x42000000

    mov r1, #0xff

    str r1, [r0]           @将r1里面的数据存储到r0指向的内存地址   *r0 = r1

     

    =======================  基址变址寻址  =================

    ======  前索引 ========

    mov r0, #0x41000000        @0x40000000,0x42000000

    mov r1, #0xff

    str r1, [r0, #4]           @将r1里面的数据存储到r0+4指向的内存地址   *(r0+4) = r1

    =========  自动索引 ====

    mov r0, #0x41000000        @0x40000000,0x42000000

    mov r1, #0xff

    str r1, [r0, #4]!           @将r1里面的数据存储到r0+4指向的内存地址,然后r0自动加4   *(r0+4) = r1  r0 = r0+4

    =========  后索引 =====

    mov r0, #0x41000000        @0x40000000,0x42000000

    mov r1, #0xff

    str r1, [r0], #4          @将r1里面的数据存储到r0指向的内存地址,然后r0自动加4   *r0 = r1  r0 = r0+4

     

     

     

    数组求和:

    ldr r0, =myarray

    mov r4, #0

    loop:

    ldr r1, [r0], #4

    cmp r1, #0

    beq stop

    add r4, r1

    b loop

     

     

    用汇编实现如下功能:

    main()

    {

    int i = 0;

    char src_buf[] = {1, 2, 3};

    char dest_buf[8];

     

    for(i = 0; i < 3; i++)

    {

    dest_buf[i] = src_buf[i];

    }

    }

     

     

    .text

    .global _start

    _start:

    ldr r0, =src_buf

    ldr r1, =dest_buf

    mov r4, #0

    loop:

    cmp r4, #3

    beq stop

    add r4, #1

    ldrb r2, [r0], #1

    strb r2, [r1], #1

    b loop

     

    stop:

    b stop

     

    src_buf:

    .byte 1, 2, 3

    dest_buf:

    .space 8

    .end

    转载请注明原文地址: https://ju.6miu.com/read-14822.html

    最新回复(0)