云计算百科
云计算领域专业知识百科平台

【ARM芯片的启动程序】汇编学习

文章目录

    • 前言
    • 一、程序状态寄存器
    • 二、立即数(imm)的概念
    • 三、汇编指令
      • mov指令
      • add指令
      • sub指令
      • ldr指令
      • str指令
      • bic指令
      • orr指令
      • CMP指令
      • b指令
    • 四、s后缀
    • 五、ARM CPSR 常用条件码
    • 六、栈的分类
    • 七、汇编和C语言混合编程
      • 7.1 汇编调用C函数
      • 7.2 C调用汇编函数
    • 八、切换处理器工作模式为USER模式

请添加图片描述

前言

由于使用arm芯片时,其本身是不能直接使用C语言环境进行程序设计的,所以我们需要简单学习汇编指令来编写arm芯片的启动程序,使其能够使用C环境,即启动代码启动以后,引导程序到C语言环境下运行。换句话说启动代码的目的是为了在处理器复位以后搭建 c 语言最基本的需求。

一、程序状态寄存器

在这里插入图片描述

二、立即数(imm)的概念

8位、10位、12位

立即数的判断:

  • 如果某个数的数值范围是 0~0xFF 之间,那么这个数一定是立即数;
  • 把某个数展开成 2 进制,这个数的最高位 1 至最低位 1 之间的二进制数序列的位 数不能超过 8 位;
  • 这个数的二进制序列凑够 8 位之后的的右边必须为偶数个连续的 0
  • 例:

    • 0x234 = 0000 0000 0000 0000 0000 0010 0011 0100 最高位1至最低位1之间的二进制数序列:1000 1101没有超过8位 末尾1的右边有2个0,所以0x234是立即数

    • 0x3f4 = 0000 0000 0000 0000 0000 0011 1111 0100 最高位1至最低位1之间的二进制数序列:1111 1101 从第一个1开始到最后一个1之间没有超过8位 末尾1的右边有2个0,所以0x3f4是立即数

    • 0x132 = 0000 0000 0000 0000 0000 0001 0011 0010 最高位1至最低位1之间的二进制数序列:1001 1001 从第一个1开始到最后一个1之间没有超过8位 末尾1的右边有1个0,不满足第二条,所以0x132不是立即数

    • 0x7f8 = 0000 0000 0000 0000 0000 0111 1111 1000 最高位1至最低位1之间的二进制数序列:1111 1111从第一个1开始到最后一个1之间没有超过8位 末尾1的右边有3个0,不满足第二条,所以0x7f8不是立即数

    • 0xfab4 = 0000 0000 0000 0000 1111 1010 1011 0100 最高位1至最低位1之间的二进制数序列:0011 1110 1010 1101 从第一个1开始到最后一个1之间超过8位,不满足条件1,所以这个数不是立即数

    在这里插入图片描述 ARM 指令机器码只有12bit 用来存立即数,放不下完整 32 位数字,拆成两部分:

  • 高 4 位:rotate(旋转位,黄色块)
  • 低 8 位:imm8(8 位基础立即数,青色块)
  • 最终 32 位立即数 = imm8 循环右移 2×rotate 位(移位步数永远是偶数:0、2、4 … 30 位。) 如上图:ADD R0, R1, #0xFA00 ; 合法,汇编器算出rotate=12 imm8=0xFA,填入机器码12bit

    三、汇编指令

    mov指令

    加载12位立即数到寄存器或转移一个寄存器的值到另外一个寄存器; MOV{S}<c> <Rd>, #<const>

    例: mov r0, #2 ;加载立即数2到寄存器r0

    MOV{S}<c> <Rd>, <Rm>

    例: mov r1, r0 ;将r0寄存器的值加载到r1

    add指令

    ADD{S}<c> <Rd>, <Rn>, #<const>

    例: ADD R0, R1, #1 ; R0 = R1 + 1,不更新标志 ADDS R0, R1, #0xFF ; R0 = R1 + 0xFF,更新N/Z/C/V

    ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}

    例: ADD R0, R1, R2 ; R0 = R1 + R2 ADD R0, R1, R2, LSL #2 ; R0 = R1 + (R2 << 2)

    sub指令

    SUB{S}<c> <Rd>, <Rn>, #<const>

    例: SUB R0, R1, #5 ; R0 = R1 − 5,不更新标志 SUBS R0, R1, #0x10 ; R0 = R1 − 0x10,更新N/Z/C/V

    SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}

    例: SUB R0, R1, R2 ; R0 = R1 − R2 SUB R0, R1, R2, LSL #1 ; R0 = R1 − (R2 << 1)

    ldr指令

    功能1:将非立即数加载到通用寄存器 LDR{<c>}{<q>} <Rt>, <label>

    例:如ldr r0, =0x2FAB4

    功能2:将RAM中的数据加载到通用寄存器 LDR<c> <Rt>, [<Rn>{, #+/-<imm12>}]

    例:ldr r0,[r1,#4];将内存地址为R1+4的字数据读入寄存器R0

    LDR<c> <Rt>, [<Rn>], #+/-<imm12>

    例:ldr r0, [r1], #8 ;将内存地址R1的字数据读入r0,之后r1+8

    LDR<c> <Rt>, [<Rn>, #+/-<imm12>]!

    例:LDR R0,[R1,#8] ! ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1。

    str指令

    将通用寄存器中的值写入到RAM中

    str r1, [r0] ;*r0 = r1
    str r1, [r0, #4] ;*(r0 + 1) = r1
    str r1, [r0], #4 ;*r0++ = r1
    str r1, [r0, #4]! ;*++r0 = r1

    bic指令

    将某个通用寄存器清零(操作数中为bit1的位清0),清0结果写回到通用寄存器。 BIC{S}<c> <Rd>, <Rn>, #<const>; 将rn中的字数据const为1的比特清零,把结果放入rd。

    例: mov r0, #0xff bic r0, #1 此时r0中的值为0xfe

    orr指令

    将某个通用寄存器置1(操作数中为bit1的位置1),置1结果写回到通用寄存器

    例: mov r0, #0 orr r0, #(1 << 6) ;0100 0000 此时r0中的值为0100 0000。

    CMP指令

    比较两个寄存器的值或者比较一个寄存器和立即数的值,其原理是对待比较的两个数求差,看结果是否为0,这个指令会无条件修改N,V,C,Z位。

    例: mov r0, #100 cmp r0, #100 会导致Z置位,从条件码表可知,只要Z置位就是两数相等。

    b指令

    实现无条件跳转; b指令条件分支 b指令循环 b函数调用 bl指令:函数跳转前,会将函数返回地址保存到lr寄存器; bx指令:bx lr 等价于mov pc, lr,bx指令加一个地址。

    使用示例: 在这里插入图片描述 在这里插入图片描述

    四、s后缀

    汇编指令的 s 后缀,几乎所有的汇编指令都可以在指令后面加上 s 后缀,s 后缀的含义是在指令执行过程中会更新 cpsr 寄存器的 N,V,C,Z 位。

    例:

    • ADDS R3,R0,R1 ; R3 = 0,带S,更新标志:Z=1,C=1
    • SUBS R3,R0,R1 ; R3 = 0xFFFFFFFB,带S更新标志; 结果负数 N=1;发生借位 C=0;无符号溢出V=0;Z=0

    五、ARM CPSR 常用条件码

    后缀英文全称判断条件含义类型
    EQ Equal Z=1 等于 通用
    NE Not Equal Z=0 不等于 通用
    CS/HS Carry Set / Higher or Same C=1 进位置1 / 无符号≥ 无符号比较
    CC/LO Carry Clear / Lower C=0 进位清零 / 无符号< 无符号比较
    MI Minus N=1 结果为负数 符号判断
    PL Plus N=0 结果非负(≥0) 符号判断
    VS Overflow Set V=1 有符号溢出 溢出判断
    VC Overflow Clear V=0 无有符号溢出 溢出判断
    GT Greater Than N==V && Z==0 有符号> 有符号比较
    GE Greater or Equal N==V 有符号≥ 有符号比较
    LT Less Than N!=V 有符号< 有符号比较
    LE Less or Equal `N!=V Z==1`

    例:

    • CMP R0, R1 ; R0‑R1,更新标志,Z=1 ADDEQ R2, R2, #1 ; ✅条件成立,R2 = R2 +1

    • cmp r0, r1 blt lable1 bgt lable2 执行 R0‑R1 的运算并更新 CPSR 状态标志,不保存运算结果;blt lable1为有符号小于条件跳转,若满足有符号 R0<R1(N≠V),就跳转到 lable1;bgt lable2为有符号大于条件跳转,若满足有符号 R0>R1(N==V 且 Z=0),就跳转到 lable2;

    六、栈的分类

    在这里插入图片描述 满栈/空栈(是一种结构,不是传统字面意思的满空):根据栈顶所在位置是否存有元素确定。 栈顶所在位置一直存有元素称为满栈,先移动栈顶再存入数据; 栈顶所在位置一直没有元素称为空栈,先存入数据再移动栈顶。

    增栈/减栈:根据栈的生长方向确定。 入栈数据时,栈顶向内存高地址移动,称为增栈; 入栈数据时,栈顶向内存低地址移动,称为减栈,

    注意:ARM中的栈结构为:满减栈。

    七、汇编和C语言混合编程

    汇编调用C函数C调用汇编函数

    7.1 汇编调用C函数

    汇编和C语言混合编程(汇编调用C函数C调用汇编函数) 汇编如何向c语言传参: C语言将函数运行结果返回给R0寄存器 当参数小于等于4个时,通过通用寄存器进行传参(R0-R3) 在这里插入图片描述

    当参数超过4个时,必须通过栈进行传参(入栈保护出栈恢复) 在这里插入图片描述

    7.2 C调用汇编函数

    C语言向汇编函数传参,参数会被保存到通用寄存器汇编函数的结果通过R0寄存器返回给C语言 在这里插入图片描述

    八、切换处理器工作模式为USER模式

    1.将cpsr寄存器中的值读到R0寄存器 2.将R0寄存器中的值修改为10000 3.将R0寄存器中的值写回到cpsr寄存器 mrs指令:读取某个特殊寄存器(cpsr)的值到通用寄存器 msr指令:将通用寄存器中的值写入到特殊寄存器(cpsr)

    例: MRS , <spec_reg> mrs r0, cpsr MSR<spec_reg>, msr cpsr, r0

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【ARM芯片的启动程序】汇编学习
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!