嵌入式软件常用面试题汇总之Linux系统相关(3)
Linux系统之内核驱动基础相关的面试题汇总
对于应届生校招类,面试时候基本上只要关键词有达到就可以了。
1.你了解交叉编译吗?讲一下交叉编译的作用?为什么需要交叉编译器?交叉编译器的版本?如何获取交叉编译器?
作用:
交叉编译的作用是在一种平台(x86)上生成可以在另一种不同平台(arm)上执行的代码。
原因:
不同体系结构的目标平台:目标平台和开发平台可能采用不同的指令集架构(比如ARM和x86),因此需要将代码从一个平台编译成另一个平台可执行的代码。
资源限制:在一些嵌入式系统或者低端设备上,可能没有足够的资源来运行一个完整的编译环境,因此需要在更强大的开发机器上进行编译。
开发效率:有时为了节省时间,可以在一台性能更好的机器上进行编译,然后将生成的可执行文件移植到目标平台上,而不是在目标平台上直接编译。
版本:
交叉编译器的版本取决于目标平台和开发环境。常见的交叉编译器包括GCC(GNU Compiler Collection)和Clang/LLVM。
获取交叉编译器通常可以通过以下方式:
源码编译:从交叉编译器项目的官方网站或版本控制库获取源代码,然后在开发机器上编译安装。这通常需要具备一定的编译环境和相关依赖项。
预编译包:有些操作系统或软件发行版可能提供了预编译好的交叉编译器,可以直接通过软件包管理器安装。
交叉编译工具链:有些嵌入式开发平台提供了针对特定硬件和软件组合的交叉编译工具链,可以从它们的官方渠道获取。
2.linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些?
对 32 位操作系统而言,它的寻址空间(虚拟地址空间,或叫线性地址空间)为 4G(2的32次方)。也就是说一个进程的最大地址空间为 4G。操作系统的核心是内核(kernel),它独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证内核的安全,现在的操作系统一般都强制用户进程不能直接操作内核。具体的实现方式基本都是由操作系统将虚拟地址空间划分为两部分,一部分为内核空间,另一部分为用户空间。针对 Linux 操作系统而言,最高的 1G 字节(从虚拟地址 0xC0000000 到 0xFFFFFFFF)由内核使用,称为内核空间。而较低的 3G 字节(从虚拟地址 0x00000000 到 0xBFFFFFFF)由各个进程使用,称为用户空间。
用户空间与内核通信方式主要有:
系统调用(System call):用户空间的进程通过系统调用向内核发出请求,请求内核代表其执行特权操作,如文件操作、进程管理等。系统调用提供了一种安全的用户空间与内核空间通信的方式。
文件系统:很多内核程序细节,如中断等,都在proc/目录下有所体现,虚拟文件系统提供了一种便捷的用户空间和内核空间的交互方式。用户空间的进程可以通过文件系统接口直接读写文件,而文件系统底层由内核来管理。
内存映射:mmap共享内存。Linux通过mmap的把内核中特定部分的内存空间映射到用户级程序的内存空间去,从而提供了用户程序对内存直接访问的能力。该方式尤其适合在那些内核和用户空间需要快速大量交互数据的情况下。
内核程序使用信号通知应用程序:信号在内核里的用途主要集中在通知用户程序出现重大错误,强行杀死当前进程,这是内核通过发送SIGKILL信号通知进程终止。
管道(Pipes): 管道是一种特殊的文件,可以在进程间进行通信。它可以用于用户空间进程之间的通信,而管道的底层实现是通过内核来管理的。
3.为什么区分内核空间跟用户空间
在 CPU 的所有指令中,有些指令是非常危险的,如果错用,将导致系统崩溃,比如清内存、设置时钟等。如果允许所有的程序都可以使用这些指令,那么系统崩溃的概率将大大增加。
所以,CPU 将指令分为特权指令和非特权指令,对于那些危险的指令,只允许操作系统及其相关模块使用,普通应用程序只能使用那些不会造成灾难的指令。比如 Intel 的 CPU 将特权等级分为 4 个级别:Ring0~Ring3。
其实 Linux 系统只使用了 Ring0 和 Ring3 两个运行级别(Windows 系统也是一样的)。当进程运行在 Ring3 级别时被称为运行在用户态,而运行在 Ring0 级别时被称为运行在内核态。
通过区分内核空间和用户空间的设计,隔离了操作系统代码(操作系统的代码要比应用程序的代码健壮很多)与应用程序代码。即便是单个应用程序出现错误也不会影响到操作系统的稳定性,这样其它的程序还可以正常的运行。
5.什么是内核态和用户态?
当进程运行在内核空间时就处于内核态,而进程运行在用户空间时则处于用户态。
在内核态下,进程运行在内核地址空间中,此时 CPU 可以执行任何指令。运行的代码也不受任何的限制,可以自由地访问任何有效地址,也可以直接进行端口的访问。
在用户态下,进程运行在用户地址空间中,被执行的代码要受到 CPU 的诸多检查,它们只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址,且只能对任务状态段(TSS)中 I/O 许可位图(I/O Permission Bitmap)中规定的可访问端口进行直接访问。
6.静态库与动态库的区别?
叫静态库是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中,所以占用内存会比较大。
而动态库是在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入,占用内存少。
链接方式:
静态库: 在编译链接阶段,静态库的代码会被复制到最终的可执行文件中。因此,可执行文件在运行时不再需要依赖于静态库。
动态库: 在编译链接阶段,只有对动态库的引用会被链接到最终的可执行文件中,而实际的库文件代码不会被复制。动态库在程序运行时由操作系统动态加载到内存中,并与程序共享。
文件大小和内存占用:
静态库: 包含了所有的代码和数据,因此可执行文件的大小会比较大,且在每个使用该静态库的程序中都会有一份拷贝。
动态库: 多个程序可以共享同一个动态库,因此节省了存储空间,并且在内存中只需要一份动态库的副本,因此通常在内存占用上更加高效。
更新和维护:
静态库: 如果静态库更新了,所有使用该静态库的程序都需要重新编译以包含更新后的代码。因此,更新和维护静态库可能比较繁琐。
动态库: 如果动态库更新了,只需要替换系统中的动态库文件,所有使用该动态库的程序都可以自动享受到更新,无需重新编译。
加载和运行效率:
静态库: 在程序启动时,所有静态库的代码都被加载到内存中,可能导致程序启动较慢,但运行时的性能可能稍微好一些。
动态库: 只有在需要时才会被加载到内存中,因此程序启动速度可能更快,但运行时可能稍微慢一些,因为需要动态加载和链接库。
7.什么是设备树?
Linux设备树(Device Tree)是一种描述硬件平台信息和设备配置的数据结构,用于在Linux内核启动时传递硬件信息给内核。它是一种独立于硬件架构的描述性文档,被设计用来描述系统的硬件组件、设备连接、资源分配以及其他相关信息。
设备树通常由一个文本文件(通常是以.dts或.dtsi为扩展名的文件)来描述,这个文件描述了系统的硬件组件、连接方式以及设备的属性。然后通过设备树编译器(如dtc)将设备树编译成二进制格式(.dtb文件),内核启动时加载这个二进制设备树文件,并根据其中描述的硬件信息初始化系统。
使用设备树的主要优点包括:
硬件抽象: 设备树提供了一种硬件抽象的方法,使得内核不需要静态了解硬件细节就能在不同平台上运行。
简化内核编译: 设备树允许内核作为一个通用映像在不同的硬件上运行,而无需为每个硬件平台编译一个特定的内核。
灵活性: 设备树可以描述复杂的硬件连接和配置,允许系统构建者灵活地配置系统。
可维护性: 设备树文件提供了一种可读性较高的描述硬件的方式,使得系统的硬件配置和修改更加直观和可维护。
8.copy_to_user()和copy_from_user()主要用于实现什么功能?
copy_to_user() 和 copy_from_user() 是 Linux 内核中用于用户空间和内核空间之间数据传输的函数。
从内核空间向用户空间复制数据(copy_to_user()): 当用户程序需要获取内核中的数据时,内核通过 copy_to_user() 函数将数据从内核空间复制到用户空间。这个函数会验证用户空间指针的有效性,并确保数据传输的安全性和正确性。
从用户空间向内核空间复制数据(copy_from_user()): 当用户程序需要将数据传递给内核时,内核通过 copy_from_user() 函数将数据从用户空间复制到内核空间。这个函数同样会验证用户空间指针的有效性,并确保数据传输的安全性和正确性。
9.linux中主要有哪几种设备?
Linux 内核中主要有三种类型的设备:
字符设备(Character Device): 这种设备以字符为单位进行数据传输。它们是按顺序访问的,没有块的概念。典型的字符设备包括终端设备(如键盘和显示器)、串口设备(如串口通信设备)、声卡等。字符设备的特点是每次读取或写入都是一次性的,而且通常没有缓冲区,数据被直接传送到设备。
块设备(Block Device): 这种设备以块(通常是几KB或更大)为单位进行数据传输。块设备通常具有缓冲区,并支持随机访问,可以按任意顺序读取或写入数据。典型的块设备包括硬盘驱动器、固态硬盘(SSD)、CD-ROM 等。
网络设备(Network Device): 这种设备通过网络进行数据传输,通常用于网络通信。典型的网络设备包括网卡(Network Interface Card,NIC)和无线网卡(Wireless Network Interface Card,Wi-Fi)等。
10.字符设备和块设备的区别?
数据传输单位: 字符设备以字符为单位进行数据传输,而块设备以块为单位进行数据传输。
访问方式: 字符设备通常按顺序访问,没有块的概念,而块设备支持随机访问,可以按任意顺序读取或写入数据。
缓冲区: 字符设备通常没有缓冲区,数据被直接传送到设备,而块设备通常具有缓冲区,数据先被缓存,然后批量传送到设备。
用途: 字符设备通常用于需要按顺序访问的设备,如终端设备和串口设备;而块设备通常用于需要随机访问和较大数据传输的设备,如硬盘驱动器和固态硬盘。
11.insmod 一个驱动模块,会执行模块中的哪个函数?
module_init()。这个函数的原型定义在 <linux/init.h> 头文件中
12.设备驱动模型三个重要成员是?platform总线的匹配规则是?
设备(Device): 代表系统中的一个硬件设备,例如磁盘、网卡、键盘等。每个设备都有一个唯一的标识符(如设备号或者设备路径),用于在系统中唯一标识这个设备。
驱动程序(Driver): 是与特定硬件设备相对应的软件模块,负责控制设备的操作。驱动程序通常包含初始化函数、读取函数、写入函数等,用于与设备进行交互。
总线(Bus): 是用于连接设备和驱动程序的物理或逻辑总线,例如 PCI 总线、USB 总线、SPI 总线等。总线负责管理设备和驱动程序之间的通信和交互。
要匹配的设备和驱动都要注册,设备可以在设备树里注册,也可以通过代码注册设备,匹配成功会去调用驱动程序里的probe函数。
#牛客在线求职答疑中心##嵌入式##软件开发2024笔面经##2024届春招##linux驱动#该专栏是我整理的一些嵌入式软件笔面试常见的题目,在有一定计算机基础上,再过一遍该专栏的内容,对应届生校招来说基本上笔面试就没什么问题了! 有任何疑问可随时与我联系,一起交流一起进步。