笔试题笔试题1.ARM指令中B和BLX的区别?B:跳转执行B指令的格式为:B{条件}目标地址B指令是最简单的跳转指令。遇到B指令,ARM处理器会立即跳转到给定的目标地址,并从那里继续执行。注意,跳转指令中存储的实际值是相对于当前PC值的偏移量,不是绝对地址,它的值是由汇编程序计算出来的(参考寻址方式中的相对寻址)。是一个24位有符号数,左移两位后符号扩展为32位,表示的有效偏移量为26位(前后32MB的地址空间)。示例:BLabel;程序无条件跳转到标号Label处执行CMPR1,#0;当CPSR寄存器中的Z条件码置位后,程序跳转到标号Label执行BEQLabelBLX跳转,并进行链接和状态切换。结合BX和BL功能。BLX指令的格式为:BLX目标地址BLX指令从ARM指令集跳转到指令指定的目标地址,将处理器的工作状态从ARM状态切换到Thumb状态。该指令还将PC的当前内容保存到寄存器R14中。因此,当子程序使用Thumb指令集而调用方使用ARM指令集时,可以通过BLX指令实现子程序的调用和处理器工作状态的切换。总结1、BL和BLX指令可以将下一条指令的地址复制到lr(r14,链接寄存器)。2.BX和BLX指令可以改变处理器的状态,从ARM到Thumb,或者从Thumb到ARM。3.BLX标签无论在什么情况下都会一直改变处理器的状态。4.BXRm和BLXRm可以从Rm的位[0]推导出目标状态。5.如果Rm的bit[0]为0,则处理器状态变为(或保持)ARM状态。如果Rm的位[0]为1,则处理器状态更改为(或保持)Thumb状态。2.当ARM处理器架构中出现IRQ时,处理器会执行哪些操作?中断发生后,ARM内核的运行步骤可以概括为4大步和3小步。1、4大3小步保存执行状态:将CPSR复制到出现异常模式的SPSR中;模式切换:强制CPSR模式位设置为异常类型对应的值,处理器进入ARM执行模式,禁止所有IRQ中断,进入FIQ快速中断模式时禁止FIQ中断;savereturnaddress:将下一条指令(中断程序)的地址保存在LR中(异常模式下为LR_except)。跳转到异常向量表:强制PC的值设置为对应的异常向量地址,跳转到异常处理程序。二、详细步骤1、保存执行状态当前程序的执行状态保存在CPSR中。当异常发生时,当前CPSR中的执行状态应该保存在异常模式下的SPSR中。当将来异常返回时,它会被恢复到CPSR。,恢复执行状态。2、模式切换硬件根据当前异常类型,自动将异常代码写入CPSR中的M[4:0]模式位,使CPU进入相应的异常模式。不管是ARM态还是THUMB态发生异常,都会自动切换到ARM态进行异常处理。这是硬件自动完成的,CPSR[5]置0。同时CPU会关闭中断IRQ(设置CPSR寄存器的I位),防止中断进入。如果当前快速中断FIQ异常,则关闭快速中断(设置CPSR寄存器的F位)。3.保存返回地址当前程序被异常中断,切换到异常处理程序,异常处理后返回当前中断模式继续执行,所以需要保存下一条指令的地址当前执行的指令到LR_except(异常在LR模式下,没有LR_excep寄存器,为了方便读者,加上_excep,下面同理)。由于异常模式不同,且ARM内核采用流水线技术,在异常处理程序中应根据异常模式计算返回地址。4.跳入异常向量表这个操作是由CPU硬件自动完成的。当异常发生时,CPU强制修改PC的值到固定的内存地址。这个固定地址称为异常向量。3、ARM状态和Thumb状态的切换指令是什么?举个例子来说明这个概念。ARM状态arm处理器工作在32位指令状态。所有指令都是在32位thumb状态arm执行16位指令的状态,即16位状态切换指令从arm状态切换到thumb状态。设置寄存器最低位为1BX指令:R0[0]=1,然后执行BXR0指令,进入thumb状态从thumb状态切换到ARM状态寄存器,设置最低位为0BX指令:R0[0]=0,执行BXR0指令,进入布防状态。例如,AREAArm_to_Thumb,CODE,READONLYENTRYCODE32startldrr0,=aaa+1movr3,#18bxr0CODE16aaamovr1,#12movr2,#10END4。ARM支持哪些异常类型,请列出中断向量地址。异常来源分类要进入异常模式,必须有一个异常来源。ARM规定了7种异常源:异常向量表是一个特定的内存地址空间,每一个ARM异常对应一个字长空间(4Bytes),恰好是一个32位的Instructionlength,当异常发生时,CPU强制将PC的值设置为当前异常对应的固定内存地址。异常向量表:从异常向量表跳转到异常向量表的操作在异常发生时由硬件自动完成,剩下的异常处理任务完全交给程序员。从上表可以看出,异常向量是一个固定的内存地址,我们可以向这个地址写一个跳转指令,让它跳转到我们自己定义的异常处理器的入口,然后就可以完成异常处理了。正是因为异常向量表的存在,才将硬件异常处理和程序员自定义的handler有机地联系在一起。异常向量表中地址0x00000000为复位异常。之所以在地址0是因为CPU上电时会自动从地址0加载指令。可以看出在这个地址安装resetexception也是前后端结合的设计。是的,不得不惊叹CPU设计者的伟大。在它们的后面是剩下的七个异常向量。每个异常向量占用四个字节,恰好是一条指令的大小。最后一个异常是快速中断异常。Installit在这里也有它的意义,快速中断处理程序可以直接存放在0x0000001C地址,不用设置跳转指令,可以节省一个时钟周期,加快快速中断处理时间。内存映射地址0x00000000是为向量表保留的。在一些处理器中,向量表可以选择位于高地址0xFFFF0000[可以通过协处理器指令配置]。为了控制内存访问权限,现在的操作系统通常会启用虚拟内存。启用虚拟内存后,内存启动空间通常是内核进程空间,页表空间,异常向量表不能再放在0地址。比如Cortex-A8系统支持放置第一个通过设置CP15的C12寄存器来获取任意地址的异常向量表地址。5.Linux与外设的通信是分层的,请画出外设寻址的分层模型。这个问题有点不清楚在问什么,如果分析有误,请留言。Linux下万物皆文件,访问外设的应用需要通过驱动来操作外设。Linux下的设备类型分为:字符设备、块设备、网络设备。架构图参考下图:另外,题目要求画出外设寻址的分层模型。我想它可能会问如何访问SDRAM。如下图,CPU要访问SDRAM或者flash,需要先通过AHB总线,再通过外部存储器接口控制器寻址外部存储器,然后读写数据。访问外部存储器6.中断是嵌入式系统的重要组成部分。中断服务程序通常需要满足哪些要求?中断是嵌入式系统的重要组成部分。许多外围设备和CPU通过中断进行交互。衡量一个OS实时性的一个很重要的特征就是中断响应时间,中断时间长,所以中断响应。一旦进入中断状态,cpu就被占用了,所以必须迅速释放中断,否则会影响整体性能。中断服务程序需要满足以下要求:不能返回值;无法将参数传递给ISR;ISR应尽可能短;中断应尽快发出;耗时中断应该放在中断的下半部分;不应调用中断,因为它会休眠功能;通常,浮点运算不在中断中执行;不可重入函数不能在中断函数中调用,可能会出现意想不到的问题。7、在使用共享资源时,为了使它们满足互斥条件,通常有哪些方法?共享资源也称为关键资源。它们在进程、线程、内核下都有自己的同步和互斥机制。如果只考虑互斥,单独看:进程:信号量(值设置为1)线程:互斥量、信号量(也叫信号量)内核:原子操作、自旋锁、信号量、互斥锁8.什么是同步嵌入式操作系统通信服务?Linux进程间通信主要包括信号量、信号量、管道、消息队列、共享内存套接字(本地和域套接字)9、请举例说明什么是可重入函数和不可重入函数。1.不可重入函数在实时系统的设计中,经常会出现多个任务调用同一个函数的情况。如果一个函数不幸被设计成不可重入的,那么不同的任务在调用这个函数的时候可能会修改其他调用这个函数的任务的数据,造成不可预知的后果。这样的函数是不安全函数,也叫不可重入函数。大多数满足以下条件的函数都是不可重入的。函数体中使用静态数据结构;函数体中调用了malloc()或free()函数(malloc和free是不可重入函数);标准I/O功能。2.可重入函数一个可重入函数可以被多个任务调用而不用担心数据损坏。可重入函数可以随时中断,并且可以在一段时间后再次运行而不会丢失相应的数据。可重入函数或仅使用局部变量,局部变量存储在CPU寄存器或堆栈中;或者使用全局变量,那么全局变量一定要protected怎么写可重入函数,不要访问函数体中的那些全局变量,不要使用Static局部变量,坚持只使用默认状态(auto)的局部变量,写出来的函数会可重入。如果必须访问全局变量,请记住使用互斥信号量保护全局变量。或者调用本函数前关闭中断,调用本函数后打开中断。Linux中常见的可重入函数3.例子A)可重入函数voidstrcpy(char*dest,char*src){while(*dest++=*src++);*dest=0;}B)不可重入函数1chartemp;//全局变量voidswapchar(char*x,char*y){temp=*x;*x=*y;*y=temp;//访问的全局变量}C)不可重入函数2voidswapchar(char*x,char*y){chartemp;//局部变量temp=*x;*x=*y;*y=temp;//使用全局变量}4.使用不可重入函数的注意事项intExam=0;unsignedintexample(intpara){unsignedinttemp;Exam=para;//(**)temp=Square_Exam();returntemp;}Exam是一个int型全局变量,函数Squre_Exam()返回Exam的平方值,所以函数example()不会有重入性。如果这个函数被多个进程调用,结果可能是未知的,因为在执行Exam=para语句的时候,可能会激活另一个使用这个函数的进程,那么当新激活的进程执行这个函数时,Exam就会被赋予不同的参数值,因此当控件返回到“temp=Square_Exam()”时,计算出的temp可能不是预期的结果。这个函数应该改进如下:intExam=0;unsignedintexample(intpara){unsignedinttemp;[应用信号量操作]//(1)lockExam=para;temp=Square_Exam();[释放信号量操作]//unlockreturnttemp;如果无法应用“信号量”,则意味着另一个进程正在为Exam赋值并计算其平方(即使用此信号)。这个进程必须等待信号释放后才能继续执行。如果应用了该信号,它可以继续执行,但其他进程必须等待该进程释放信号量后才能使用该信号。5.可重入函数可重入函数10.int*fun(void)和int(*fun)(void)有什么区别?int*fun(void)fun是一个函数名,参数为void,返回值为int*int(*fun)(void)fun是一个函数指针,用来指向一个函数,函数的参数函数为void类型,返回值为int,即类型如下:intfunction(void){return0;}11。在32位系统上有如下C程序:structperson{inta;unsignedshortintm;charb;char*q;charc;};charstr[]="yikoulinux";char*p=str;intn=10;然后sizeof(str),sizeof(p),sizeof(n),sizeof(int),sizeof(structperson)的值分别为:编写测试程序1#include
