嵌入式培训 百分网手机站

嵌入式软件助理工程师认证考试试题题库(4)

时间:2018-04-01 11:42:31 嵌入式培训 我要投稿

2016年嵌入式软件助理工程师认证考试试题题库

  答:

  在Linux中启动一个进程有手工启动和调度启动两种方式:

  (1)手工启动

  用户在输入端发出命令,直接启动一个进程的启动方式。可以分为:

  ①前台启动:直接在SHELL中输入命令进行启动。

  ②后台启动:启动一个目前并不紧急的进程,如打印进程。

  (2)调度启动

  系统管理员根据系统资源和进程占用资源的情况,事先进行调度安排,指定任务运行的时间和场合,到时候系统会自动完成该任务。

  27、简述Bootloader有何作用?

  答案要点:(1)首先,bootloader是在特定硬件平台运行的程序,严重依赖于硬件平台,需要移植;(2)是系统上电之后,第一个运行的程序,系统在上电或复位时通常都从地址 0x0 处开始执行,而在这个地址处安排的通常就是系统的 Boot Loader 程序;(3)bootloader程序的设计目标是启动嵌入式操作系统,嵌入式操作系统的启动需要一定的条件,这些条件由bootloader来满足;(4)Bootloader一般具有对存储器和网络接口操作的功能;如擦除、读写Flash,通过USB、串口下载文件等

  28、ARM处理器中,引起异常的原因是什么?

  答:(1)、指令执行引起的异常

  软件中断、未定义指令(包括所要求的协处理器不存在是的协处理器指令)、预取址中止(存储器故障)、数据中止。

  (2)、外部产生的中断

  复位、FIQ、IRQ。

  29、程序、进程、线程有何区别?

  答案要点:程序是编译后形成的可执行代码,是静止的。进程是程序的一次执行,是活动的。线程是进程的可执行单元,同一进程的不同线程共享进程的资源和地址空间。

  30、Linux系统中线程的同步方式有互斥量、信号量和条件变量等。假设现在需要设计一个多线程的应用程序,试分析一下以上几种同步方式分别可在什么场合下使用(6分)。

  参考答案:

  Mutex互斥量,用于操作某个临界资源时对该资源上锁,以实现互斥地对独占资源的使用(2分)

  Semophore信号灯,信号灯内有一计数器,可以用于对多个同类资源的分配。当资源用完时,申请资源的线程会在信号量上睡眠,有线程释放资源时,再将该线程唤醒继续运行。(2分)

  Condition条件变量,条件变量用于等待信号。当一个线程需要等待某个信号时,就可到条件变量上等待,当信号具备时,系统会唤醒该线程继续运行。(2分)

  31、简述嵌入式系统的几个重要特征?

  答案要点:系统内核小;专用性强 ;系统精简 ;高实时性的系统软件 ;多任务的操作系统 ;需要专用的开发工具和环境。 答出上述4个并适当阐述的即可给满分。

  32、什么是程序的局部性原理?

  答案要点:程序的局部性原理是指程序在执行过程中的一个较短时期内,它所执行的指令和访问的存储空间分别局限在一定的区域内。具体表现在时间局部性和空间局部性。时间局部性是指一条指令的一次执行和下一次执行、一个数据的一次访问和下一次访问,都集中在一个较短的时间内。空间局部性是指程序执行了某条指令,则它相邻的几条指令也可能马上执行。

  33、简述Busybox的工作原理。(4分)

  参考答案:Busybox是通过一个程序去实现原来Linux的众多命令程序。这样可使原来3.5MB左右的工具包压缩大约200KB大小一个程序,这对嵌入式系统非常重要(2分)。

  为了使用的方便,Busybox通过创建其原文件的符号连接来达到传递具体执行命令的目的。例如,创建一个mv的符号连接,当用户键入mv后,mv实际上会以C语言中的argv[0]传递给Busybox的主程序。这样Busybox就可据此跳转到相应的代码去执行。(2分)

  34、Linux作为嵌入式操作系统的优势?

  答:

  Linux作为嵌入式操作系统的优势主要有以下几点:

  1. 可应用于多种硬件平台。Linux已经被移植到多种硬件平台,这对于经费,时间受限制的研究与开发项目是很有吸引力的。原型可以在标准平台上开发后移植到具体的硬件上,加快了软件与硬件的开发过程。Linux采用一个统一的框架对硬件进行管理,从一个硬件平台到另一个硬件平台的改动与上层应用无关。(1分)

  2. Linux的高度模块化使添加部件非常容易。本身内置网络支持,而目前嵌入式系统对网络支持要求越来越高。(1分)

  3. Linux是一个和Unix相似、以内核为基础的、具有完全的内存访问控制,支持大量硬件(包括X86,Alpha、ARM和Motorola等现有的大 部分芯片)等特性的一种通用操作系统。(1分)

  4. Linux可以随意地配置,不需要任何的许可证或商家的合作关系。其程序源码全部公开,任何人可以修改并在GUN通用公共许可证(GNU General Public License)下发行。这样,开发人员可以对操作系统进行定制,适应其特殊需要。(1分)

  5. Linux带有Unix用户熟悉的完善的开发工具,几乎所有的Unix系统的应用软件都已移植到了Linux上。其强大的语言编译器GCC,C++等也可以很容易得到,不但成熟完善,而且使用方便。(分)

  35、简述Linux需要进行进程调度的时机(6分)

  参考答案:(每小点1分)

  Linux执行进程调度一般是在以下情况发生的:

  (1)正在执行的进程运行完毕;

  (2)正在执行的进程调用阻塞原语将自己阻塞起来进入等待状态;

  (3)正在执行的进程调用了P原语操作,从而因资源不足而被阻塞;或调用了V原语操作激活了等待资源的进程队列;

  (4)执行中的进程提出I/O请求后被阻塞;

  (5)系统分配的时间片已经用完;

  以上都是CPU为不可剥夺方式下的引起进程调度的原因。在CPU方式是可剥夺时,还有下面的原因:

  (6)就绪队列中的某个进程的优先级变得高于当前运行进程的优先级,从而也将引起进程调度。

  37、什么是符号链接,什么是硬链接?符号链接与硬链接的区别是什么?(6分)

  参考答案:

  链接分硬链接和符号链接。

  符号链接可以建立对于文件和目录的链接。符号链接可以跨文件系统,即可以跨磁盘分区。符号链接的文件类型位是l,链接文件具有新的i节点。(3分)

  硬链接不可以跨文件系统。它只能建立对文件的链接,硬链接的文件类型位是-,且硬链接文件的i节点同被链接文件的i节点相同。(3分)

  38、简述Boot Loader 的两种操作模式 (Operation Mode)?

  答:

  启动加载(Boot loading)模式:这种模式也称为"自主"(Autonomous)模式。也即 Boot Loader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。这种模式是 Boot Loader 的正常工作模式,因此在嵌入式产品发布的时侯,Boot Loader 显然必须工作在这种模式下。 (2.5分)

  下载(Downloading)模式:在这种模式下,目标机上的 Boot Loader 将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。从主机下载的文件通常首先被 Boot Loader 保存到目标机的 RAM 中,然后再被 Boot Loader 写到目标机上的FLASH 类固态存储设备中。Boot Loader 的这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用 Boot Loader 的这种工作模式。工作于这种模式下的 Boot Loader 通常都会向它的终端用户提供一个简单的命令行接口。(2.5分)

  39、模块的编程和普通程序的编程有哪些区别?(6分)

  参考答案:

  主要区别为:

  (1)因为内核模块运行在内核态,所以包含的头文件是内核程序相关的头文件,而普通程序则包含的是glibc的头文件(1分)

  (2)模块程序没有main函数,而是通过init_module函数在加载后初始化。(2分)

  (3)模块程序内可直接调用内核函数,而普通程序则只能通过系统调用使用内核函数。(2分)

  (4)普通用户程序可运行多次,而内核函数通常则只能加载1次(1分)。

  41、 已知C语言程序有主程序模块prog.c,prog.h,其中调用了另一模块subr.c, subr.h中的功能。试写出一个可将这两个模块编译成可执行文件pr1的makefile。(5分)

  参考答案:

  [每行1分]

  pr1: prog.o subr.o

  gcc –o pr1 prog.o subr.o

  prog.o: prog.c prog.h

  gcc –c –o prog.o prog.c

  subr.o: subr.c subr.h

  gcc –c –o subr.o subr.c

  43、简述Linux的VFS机制及其特点?(5分)

  参考答案:

  VFS是一种抽象的文件机制,内核中对文件系统的相关操作系统实际上都通过操作VFS实现,也就是说VFS是对各具体文件系统的'抽象。(3分)

  VFS使得内核其他部分无须关心不同文件系统之间的差异,使得Linux可以支持多种类型的文件系统。当然,因为增加了抽象层,会有类型转换的开销。(2分)

  44、模块的编程和普通程序的编程有哪些区别?(5分)

  参考答案:

  主要区别为:

  (1)因为内核模块运行在内核态,所以包含的头文件是内核程序相关的头文件,而普通程序则包含的是glibc的头文件(1分)

  (2)模块程序没有main函数,而是通过init_module函数在加载后初始化。(2分)

  (3)模块程序内可直接调用内核函数,而普通程序则只能通过系统调用使用内核函数。(2分)

  45、BootLoader有哪几种工作模式?各有什么特点(5分)

  参考答案:启动加载模式和下模式(2分)。前者“自主”,不需要用户干预,后者可响应用户的交互请求。(3分)

  46、简述嵌入式系统调试有哪几种方式(5分)

  参考答案:

  模拟器方式(1分)、在线仿真器方式(1分)、监控器方式(1分)、在线调试器方式,如JTAG(2分)。

  47、Qt/Embedded的主要特点是什么?(5分)

  参考答案:

  是一个专门为嵌入式系统设计的图形用户界面的工具包(1分)。支持UNIX和Windows平台(1分)。采用面向对象的思想开发(1分),开发接口与桌面的Qt相同,因此桌面应用程序可方便的移植到Qt/E(1分)。不分层的架构使得其他运行速度很快(1分)。

  48、简述嵌入式系统的开发流程。

  参考答案:

  需求分析阶段(1分)

  体系结构设计(1分)

  硬件/软件设计(1分)

  系统集成(1分)

  代码固化(1分)

  49、简述C语言中数组和指针的异同点。

  参考答案:

  相同点:(1)表达式中的数组名被编译器当作一个指向该数组第一个元素的指针(1分)

  (2)下标总是与指针偏移量相同(1分)

  (3)在函数参数的声明中,数组被编译器当作一个指向该数组第一个元素的指针(1分)

  不同点:(1)指针用于保存数据的地址,而数组用于保存数据(1分)

  (2)指针是间接访问而数组是直接访问方式(1分)

  50、什么是交叉编译?为什么要采用交叉编译(5分)

  参考答案:所谓交叉编译,是指在一个平台上编译生成在另一个平台上运行的可执行程序。(3分)。之所以采用交叉编译,是因为目标平台上不具备直接运行开发环境的条件。(2分)

  。

  51、什么是符号链接,什么是硬链接?符号链接与硬链接的区别是什么?

  参考答案:

  链接分硬链接和符号链接。

  符号链接可以建立对于文件和目录的链接。符号链接可以跨文件系统,即可以跨磁盘分区。符号链接的文件类型位是l,链接文件具有新的i节点。(3分)

  硬链接不可以跨文件系统。它只能建立对文件的链接,硬链接的文件类型位是-,且硬链接文件的i节点同被链接文件的i节点相同。(2分)

  52、简述Boot Loader的主要功能。

  参考答案:

  基本硬件设备初始化。(1分)

  设置好堆栈。 (1分)

  检测系统内存映射(memory map)。 (1分)

  将 kernel 映像和根文件系统映像从 flash 上读到 RAM 空间中。(1分)

  为内核设置启动参数,调用内核。(1分)

  53、嵌入式Linux系统的根文件系统通常应该包括哪个内容?

  参考答案:

  通常包括:init、libc库、驱动模块、必需的应用程序和系统配置脚本。(各1分)

  54、

  55、回答下面问题:

  a) 对于整形变量A=0x12345678,请画出在little endian及big endian的方式下在内存中是如何存储的。

  b) 在ARM系统中,函数调用的时候,参数是通过哪种方式传递的?

  c) 中断(interrupt,如键盘中断)与异常(exception,如除零异常)有何区别?

  答:

  a) 0x12345678

  little endian big endian 刚好反过来

  高地址--〉 0x12 低地址--〉 0x12

  0x34 0x34

  0x56 0x56

  低地址--〉 0x78 高地址--〉 0x78

  b)

  答:应用程序中使用中间寄存器及数据栈来传递参数。

  在arm汇编中,如果第1~4个参数通过r0 -r3寄存器来传递,超过4个的使用数据栈进行传递,输出函数由r0传递。

  c)所谓中断应该是指外部硬件产生的一个电信号,从cpu的中断引脚进入,打断cpu当前的运行;

  所谓异常,是指软件运行中发生了一些必须作出处理的事件,cpu自动产生一个陷入来打断当前运行,转入异常处理流程。

  56、某Linux主机的/etc/rc.d/rc.inet1文件中有如下语句,请修正错误,并解释其内容。

  /etc/rc.d/rc.inet1:

  ……

  ROUTE add –net default gw 192.168.0.101 netmask 255.255.0.0 metric 1

  ROUTE add –net 192.168.1.0 gw 192.168.0.250 netmask 255.255.0.0 metric 1

  答:修正错误:

  (1)ROUTE应改为小写:route;(2)netmask 255.255.0.0应改为:netmask 255.255.255.0;

  (3)缺省路由的子网掩码应改为:netmask 0.0.0.0;

  (4)缺省路由必须在最后设定,否则其后的路由将无效。

  解释内容:

  (1)route:建立静态路由表的命令;(2)add:增加一条新路由;

  (3)-net 192.168.1.0:到达一个目标网络的网络地址;

  (4)default:建立一条缺省路由;(5)gw 192.168.0.101:网关地址;

  (6)metric 1:到达目标网络经过的路由器数(跳数)。

  6.下述代码取自u-boot,请对其加以逐行注释和分析。

  typedef int (init_fnc_t) (void);

  init_fnc_t *init_sequence[] = {

  cpu_init,

  board_init,

  env_init,

  serial_init,

  display_banner,

  NULL,

  };

  init_fnc_t **init_fnc_ptr;

  for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)

  {

  if ((*init_fnc_ptr)() != 0) {

  hang ();

  }

  }

  4.简述2.4与2.6内核模块机制的改变对编写设备驱动程序的影响?

  答:2.4内核中,模块的编译只需内核源码头文件;需要在包含linux/modules.h之前定义MODULE;编译、连接后生成的内核模块后缀为.o。2.6内核中,模块的编译需要配置过的内核源码;编译、连接后生成的内核模块后缀为.ko;

  在2.6 内核中,内核模块必须调用宏module_init 与module_exit() 去注册初始化与退 出函数。在2.4内核中,如果初始化函数命名为init_module()、退出函数命名为cleanup_module()。

  2.4内核中,模块自身通过MOD_INC_USE_COUNT、MOD_DEC_USE_COUNT宏来管理自己被使用的计数。2.6内核提供了更健壮、灵活的模块计数管理接口try_module_get(&module)及module_put (& module)取代2.4中的模块使用计数管理宏;模块的使用计数不必由自身管理,而且在管理模块使用计数时考虑到SMP与 PREEMPT机制的影响。

  2.4 内核下,缺省情况时模块中的非静态全局变量及函数在模块加载后会输出到内核空间。2.6内核下,缺省情况时模块中的非静态全局变量及函数在模块加载后不会输出到内核空间,需要显式调用宏EXPORT_SYMBOL。

  57、论述一下问题

  (1) ARM中引起异常的原因

  (2) 在ARM体系中,异常中断向量表的大小是多少,其中每个异常中断占据多少字节

  (3) 异常中断的处理、返回过程。

  答:(1)原因主要:

  a.指令执行引起的异常

  软件中断、未定义指令(包括所要求的协处理器不存在是的协处理器指令)、预取址中止(存储器故障)、数据中止。

  b.外部产生的中断

  复位、FIQ、IRQ。

  (2)在ARM体系中,异常中断向量表的大小为32字节,其中每个异常中断占据4个字节大小,保留了4个字节空间。

  (3)ARM处理器对异常中断的响应过程是首先保存处理器当前状态、中断屏蔽位及CPSR寄存器中的各个条件标志位。这是通过将当前程序状态寄存器CPSR的内容保存到将要执行的异常中断对应的SPSR寄存器中实现的。其次设置当前程序状态寄存器CPSR中相应的位。再次将寄存器LR_mode(R14_mode)设置成返回地址。最后将PC设置成该异常中断的中断向量地址,从而跳转到对应的中断处理程序处执行。

  ARM处理器从异常中断程序中返回的过程:首先恢复被中断程序的处理器状态,也就是将SPSR_mode 内容复制到CPSR。然后返回到发生异常中断指令的下一条指令处执行,即将LR_mode(R14_mode)寄存器的内容复制到PC中。

  58、在linux中如何编译C程序,使之成为可执行文件(3分)?如何调试(3分)?

  答案:

  [问题1](3分)

  1)检查程序中.h文件所在的目录,将其加入系统PATH中;

  2)执行C编译:#gcc [源文件名] -o [目标文件名]

  3)改变目标文件为可执行文件:#chmod +x [目标文件名]

  4)如需将多个可执行文件连续执行,可用vi生成批处理文件,最后记得将该批处理文件属性改为可执行(同上一步)

  [问题2](3分)

  调试:在编译时使用-g参数,就可以使用gdb进行调试。

  59、时间片的大小对系统有什么影响?(3分)在选取时间片是应考虑哪些因素?(3分)

  参考答案:

  [问题1](3分)

  在轮转法中,时间片长度的选取非常重要,将直接影响系统开销和响应时间。如果时间片长度很小,则调度程序剥夺处理机的次数频繁,加重系统开销;反之,如果时间片长度选择过长,比方说一个时间片就能保证就绪队列中所有进程都执行完毕,则轮转法就退化成先进先出算法。

  [问题2](3分)

  影响时间片大小的主要因素有:系统响应时间、就绪进程数目和计算机处理能力

  60、模块的编程和普通程序的编程有哪些区别?(6分)

  参考答案:

  主要区别为:

  (1)因为内核模块运行在内核态,所以包含的头文件是内核程序相关的头文件,而普通程序则包含的是glibc的头文件(1分)

  (2)模块程序没有main函数,而是通过init_module函数在加载后初始化。(2分)

  (3)模块程序内可直接调用内核函数,而普通程序则只能通过系统调用使用内核函数。(2分)

  (4)普通用户程序可运行多次,而内核函数通常则只能加载1次(1分)。

  61、什么是交叉编译?为什么要采用交叉编译(5分)

  参考答案:所谓交叉编译,是指在一个平台上编译生成在另一个平台上运行的可执行程序。(3分)。之所以采用交叉编译,是因为目标平台上不具备直接运行开发环境的条件。(2分)

  62、简述嵌入式Linux系统的初始化过程(5分)

  参考答案:

  嵌入式Linux系统开机首先运行BootLoader,然后由BootLoader引导启动内核,由内核检查和初始化硬件设备,载入设备的驱动程序模块,安装root文件系统,然后内核将启动一个名为init的进程(2分)。在init运行完成并启动其它必要的后续进程后,系统开始运行,引导过程结束。init进程启动时需要读取inittab配置文件,该文件确定init在系统启动和关机时的工作特性。(3分)

  六、阅读程序题

  1. 管道是Linux中进程通信的一种方式,以下程序在父进程和子进程之间创建了一个管道,然后建立它们之间的通信,实现父进程向子进程写数据的功能。说明标号所在行代码的功能。

  #include

  #include

  #include

  #include

  #include

  int main()

  {

  int pipe_fd[2];

  pid_t pid;

  char buf_r[100];

  char* p_wbuf;

  int r_num;

  memset(buf_r,0,sizeof(buf_r)); (1)

  if(pipe(pipe_fd)<0) (2)

  {

  printf("pipe create error\n");

  return -1;

  }

  if((pid=fork())==0) (3)

  {

  printf("\n");

  close(pipe_fd[1]); (4)

  sleep(2);

  if((r_num=read(pipe_fd[0],buf_r,100))>0) (5)

  {

  printf( "%d numbers read from the pipe is %s\n",r_num,buf_r);

  }

  close(pipe_fd[0]); (6)

  exit(0);

  }

  else if(pid>0) (7)

  {

  close(pipe_fd[0]); (8)

  if(write(pipe_fd[1],"Hello",5)!=-1) (9)

  printf("parent write1 success!\n");

  if(write(pipe_fd[1]," Pipe",5)!=-1)

  printf("parent write2 success!\n");

  close(pipe_fd[1]); (10)

  sleep(3);

  waitpid(pid,NULL,0);

  exit(0);

  }

  }

  答案要点:(1) 将数据缓冲区清0 (2) 创建管道 (3) 创建子进程 (4) 关闭子进程写描述符 (5) 子进程读取管道内容 (6) 关闭子进程读描述符 (7) 父进程运行控制语句 (8) 关闭父进程的读描述符 (9) 将数据写入缓冲区

  (10) 关闭父进程写描述符

  2. 阅读下面shell程序,写出执行结果:

  #!/bin/sh

  for name in Tom Jack Harry

  do

  echo "$name is my friend"

  done

  1、答:

  Tom is my friend

  Jack is my friend

  Harry is my friend

  3. 用变量a给出下面的定义

  a) 一个指向整型数的指针(A pointer to an integer)

  b) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer)

  c) 一个有10个整型数的数组(An array of 10 integers)

  d) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers)

  e) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers)

  2、答:

  a) int *a; // A pointer to an integer

  b) int **a; // A pointer to a pointer to an integer

  c) int a[10]; // An array of 10 integers

  d) int *a[10]; // An array of 10 pointers to integers

  e) int (*a)[10]; // A pointer to an array of 10 integers

  4. 根据下面给出的声明和数据,对每个表达式进行求值并写出他的值。在每个表达式进行求值是使用原来给出的值(也就是说,某个表达式的结果不影响后面的表达式)。假定ints数组在内存中的起始位置是100,整型值和指针的长度都是4字节。