网站优化推广公司,北京软件开发公司滕迎江,企业建设门户网站成本如何,荣耀华为手机商城官方网站一、什么是汇编#xff1f;为什么学汇编#xff1f; 在之前写控制代码的时候就在想#xff1a;底层是怎么控制的#xff1f;后来经过学习知道之前所编写的代码都是应用层代码#xff0c;顾名思义就是在系统写好的底层之上调用系统函数。原以为底层是指写系统写好的底层函数…一、什么是汇编为什么学汇编 在之前写控制代码的时候就在想底层是怎么控制的后来经过学习知道之前所编写的代码都是应用层代码顾名思义就是在系统写好的底层之上调用系统函数。原以为底层是指写系统写好的底层函数类似于写linux系统函数read、open、close之类的函数。但是再往下挖read、open这类函数的下一层是什么经过系统性查资料总结了下面的流程 从上面的图可以知晓linux系统所提供的IO函数属于应用层并未涉及到最底层。open、read等函数通过file_operation结构体去调用驱动程序中的自定义的接口函数。所说的写驱动就是写自定义的device_open()、device_close()、device_write()、device_read()、device_ioctl()函数这些名字随便起。
1.1 那么这些自己编写的驱动函数是如何写入硬件设备中 众所周知机器所能识别的只有0和1二进制码如果想要写入硬件设备就要转换成二进制码写给机械。那么就又引入一个问题 我们所写的C语言代码怎么转换成二进制码转换成机械识别的指令 提一下C语言编译流程.c----.i-----.s------.o--------二进制 1.2 由此引入汇编指令 汇编语言是直接与机器打交道的机器只能读懂二进制码在不同的设备中汇编语言对应着不同的机器语言指令集通过汇编过程转换成机器指令。汇编语言是面向机器的处于整个计算机语言层次结构的底层故被视为一种低级语言。从上面的图可知预处理部分是将程序中所引用的文件打开汇编部分是将C语言转换成可被机器识别的代码针对CPU中的寄存器进行操作。 汇编是一种语言和C语言一样有自己的编写方式不过指令个人感觉有点难懂。
知道汇编是什么了但还是没有解决问题使用汇编写入硬件设备但是写进硬件设备的哪里去了至此引入最重要的一块寄存器。 二、寄存器
2.1 为什么要用寄存器 一块成熟的板子笼统分两部分CPU和内存使用流程是从CPU从内存中搬出来数据使用大致如此。 CPU 本身只负责运算不负责储存数据。数据一般都储存在内存之中CPU 要用的时候就去内存读写数据。但是CPU 的运算速度远高于内存的读写速度为了避免被拖慢CPU 都自带一级缓存和二级缓存。CPU 缓存可以看作是读写速度较快的内存。 CPU缓存还不够快并且数据在缓存的地址不固定导致CPU每次读写都会拖慢速度。因此CPU还自带寄存器用来储存最常用的数据。也就是说那些最频繁读写的数据比如循环变量都会放在寄存器里面CPU 优先读写寄存器再由寄存器跟内存交换数据。 寄存器不依靠地址区分数据而依靠名称。每一个寄存器都有自己的名称我们告诉 CPU 去具体的哪一个寄存器拿数据这样的速度是最快的。有人比喻寄存器是 CPU 的零级缓存。 总结一下就是寄存器是CPU用来存储频繁读写的数据变量之类的 比如硬件有个固定地址0x300000那么想要往这个地址里面写东西的时候就需要将地址先暂存在寄存中使用。 下面说一下寄存器种类
2.2 寄存器种类
参考文档ARM寄存器组织常见专用寄存器、控制寄存器CPSR_arm cpsr-CSDN博客 寄存器分为三种通用寄存器、专用寄存器(有特定的用途和功能只能存放指定内容的寄存器。常见的有sp、lr、pc寄存器)、控制寄存器CPSR。 2.2.1 通用寄存器
没有指定用途可以存放任意内容的寄存器既可以存放地址也可以存放参与运算的数据或者运算产生的结果。在上图中除去FIQ模式下r0-r12是通用寄存器。
2.2.2 栈指针寄存器 r13 SP
栈指针用于存储当前模式下的栈顶地址。假设现在CPU要将运算结果保存到栈上这个时候SP寄存器就会告诉CPU栈顶的位置在哪保存完毕以后SP指向的地址会更新。
2.2.3 链接寄存器 r14 LR
链接寄存器也是保存指令地址一般是发生跳转的时候事先保存跳转指令下一条指令的地址一般有两种用途
1、调用函数发生跳转 假设main函数在执行程序的时候需要调用函数func()这个时候会跳转到func() 函数的定义。由于执行完func()函数以后还要继续运行main函数在跳转之前LR寄存器会保存func()函数下一条指令的地址也就是printf函数的地址。在执行完func函数以后只需要让PC LR 就可以回到func()函数下一条指令的地址。
2、异常发生产生中断 产生异常时异常模式下的LR会自动保存被异常打断的指令的下一条指令的地址。也可以理解成是一种函数跳转。比如CPU正在忙手里的任务突然收到了网卡发来的信号CPU就会进入FIQ或者IRQ模式此时CPU就会停下手里的任务转而先去执行异常处理程序。异常处理结束后将LR的值复制到PC可实现程序返回。 没有哪个寄存器可以检测异常产生因为能检测的就不是异常产生了。产生异常的时候LR默认自动保存下一条指令的地址处理完异常情况再返回。 异常情况时要在PC特定位置执行相应错误处理由于偏移量地址是固定死的。所以当发生异常情况时会自动跳转到该异常情况的地址执行处理异常但PC寄存器是一条指令4字节并且是按照下面的顺序存放的系统要求给的只能这么写。无法在此处处理异常因为处理异常肯定不止一条指令所以这里指的都是b跳转到相应标签位置处理异常 异常的8种情况这个需要在汇编启动代码中写出来否则无法正常运行程序 偏移量地址 异常情况 注释 0x1C FIQ 快中断 0x18 IRQ 慢中断 0x14 (Reserved) 保留异常现在没有用 0x10 Data Abort 数据访问异常 访问合法空间的数据发现数据不存在访问了非法的空间越界 0x0c Prefetch Abort 指令预取异常 对程序指令预取时产生的异常 0x08 Software InterruptSWI 软中断 即User模式级别使用代码发出的中断 系统调用就是使用软中断从用户模式切换到特权模式的 0x04 Undefined Instruction 未定义异常 0x00 Reset 重启异常 模式切换到Supervisor模式 通常说的异常主要来自cpu内部abortreset等而中断主要来自外设。 从高到低的顺序依次为:Resetata Abort, FIQ, IRQ,Prefetch Abort,SWI(软中断)undefined Instruction 高优先级的异常会终止底先级的异常
上面的异常向量表在代码中的体现 2.2.4 程序指针寄存器 r15 PC 程序计数器用于存储当前取址指令的地址。我们写的程序在经过预处理、编译、汇编以后得到的二进制机器码就是指令。这些指令是被保存在内存中的CPU接下来要执行哪一条指令都是由PC控制的。 我们写程序时的逻辑是顺序执行那么CPU在执行指令的时候也是如此在ARM状态下每一条指令都占4个字节所以每执行完一条指令PC的值会自动自增4个字节地址自增4字节为下一次取指令做准备
2.2.5 控制寄存器 CPSR
CPSR很重要该寄存器里面的每个位都代表了各自含义下图有一些说明 举个例子比如在进行加法运算的时候CPSR的C位进位会变化 adc要计算十进制 3389443 但是只会计算和记录两位数于是先计算了 8943132 但是你只能记住两位数所以记下了 32然后把进位出的1扔进了CF 暂存;然后再计算 33437 顺便加上 CF 的进位得到 38跟刚才的 32 组合起来得到结果3832 相对值得注意的是工作模式由于板子在运行程序的时候肯定会遇到各种情况那么其应对各种情况也是有不同的工作模式。ARM总共有7个基本工作模式 那么体现在CPSR中MODE位不同的编码值对应不同的模式 2.3 异常处理流程 上面说完寄存器的种类后那么他工作的流程顺序是如何的
在没有异常的时候也是按照C语言执行顺序一样按顺序执行遇到特殊标记跳转。
在有异常的时候那么就需要对一些寄存器进行配置流程如下图 三、总结 简单了解完寄存器之后那么可以解决第一个问题为什么使用汇编 汇编语言的大部分语句直接对应着机器指令执行速度快效率高代码体积小 在系统程序的核心部分以及与系统硬件频繁打交道的部分可以使用汇编语言。比如操作系统的核心程序段。 缺点 不同的处理器有不同的汇编语言语法和编译器编译的程序无法在不同的处理器上执行缺乏可移植性 难懂且工作量大 C语言与汇编是可以交叉使用的C语言的好处是易懂但是要相对寄存器直接操作是很复杂的不如汇编直接了当毕竟汇编指令是直接操作寄存器的可以简单了解一些汇编指令。 自己总结的一个图简单一点可能具体情况也会更复杂。 写的文章可能还会存在缺陷我自己是这么理解的参考了其他博主一些文章文章内容觉得写得好就引用了一些勿怪勿怪。关于汇编和寄存器弄懂就好