Linux内核浮点运算保护,Linux源码解析前奏--源码初窥

一、内核简介

所谓内核即操作系统的内在核心,通常内核由中断服务程序、调度程序、内存管理程序和系统服务程序共同组成。其中,中断服务程序负责响应中断,调度程序负责管理多个进程从而分享处理器时间,内存管理程序负责管理进程地址空间,系统服务程序包括诸如网络、进程间通信等程序。

为了保护操作系统,内核独立于普通应用程序,它一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限,其执行于内核空间。与之相对的是,应用程序在用户空间执行,它只能看到允许其使用的部分系统资源,不能直接访问硬件,也不能访问内核划给别人的内存范围。

当内核运行时,系统以内核态进入内核空间执行,而执行一个普通用户程序时,系统则以用户态进入以用户空间执行。

应用程序通过系统调用或者通过库函数(例如:C库函数)间接进行系统调用来与内核通信,让内核代其完成各种不同任务。

二、源码获取

登录Linux内核官网,可以随时获取当前版本的Linux源码。可以使用Git下载和管理Linux内核源码,如下命令可以获取最新提交到Linus版本树的一个副本:

#git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git

当下载源码后,如下命令可以更新分支到Linus的最新分支:

#git pull

你也可以以补丁的形式发布对源码的修改,也可以以补丁的形式接收其他人所做的修改。要应用增量补丁,可以运行如下命令:

#patch -pl < ../patch-x.y.z

三、源码树

内核源码树由很多目录组成,而大多数目录又包含更多的子目录,具体描述如下:

目录

描述

arch

特定体系结构的源码

block

块设备I/O层

crypto

加密API

documentation

内核源码文档

drivers

设备驱动程序

firmware

使用某些驱动程序而需要的设备固件

fs

VFS和各种文件系统

include

内核头文件

init

内核引导和初始化

ipc

进程间通信代码

kernel

像调度程序这样的核心子系统

lib

通用内核函数

mm

内存管理子系统和VM

net

网络子系统

samples

示例,示范代码

scripts

编译内核所用的脚本

security

Linux安全模块

sound

语音子系统

usr

早期用户空间代码(所谓的initramfs)

tools

在Linux开发中有用的工具

virt

虚拟化基础结构

表1 内核源码树的根目录描述

四、编译源码

在编译内核源码前,你可以把自己需要的特定功能和驱动程序通过配置来编译进内核。配置选项类似于CONFIG_SMP的形式,前缀为CONFIG,SMP表示要启用或禁用的功能。

内核提供了各种工具来简化内核配置,常见的有三种:

(1)基于字符界面的命令行工具

#make config

(2)基于ncurse库的图形界面工具

#make menuconfig

(3)基于gtk+的图形界面工具

#make gconfig

你也可以用如下命令来生成默认配置:

#make defconfig

配置项会被存放在内核源码树根目录下的.config文件中,也可以直接打开这个文件修改配置选项,修改完配置文件之后编译内核之前,需要通过如下命令来验证和更新配置:

#make oldconfig

内核配置好后,就可以用如下命令来编译内核,激动人心的时刻即将到来:

#make

在编译源码时,默认会有大量信息从屏幕上一闪而过,若感不爽,可以如此这般:

#make > ../detritus

这样编译输出信息都会重定向到这个文件,如果你对此不感兴趣,可以将其扔进“黑洞”:

#make > /dev/null

内核的编译过程会有点小漫长,如果你是个急性子,可以把编译过程拆分成多个并行作业,每个作业独立并发地运行:

#make -jn

这里,n是并行作业数,一般每个处理器2个作业,即n=2*cpu,例如:32核处理器上,可以这样:

#make -j32 > /dev/null

当然也可以用distcc或者ccache来缩短内核编译时间。

编译好内核后,接下来就可以安装它了。内核的安装与体系结构和启动引导工具密切相关,对此,可以查阅启动引导工具说明,按照说明将内核映像copy到适当的位置,并按照启动要求安装它。

需要注意的是,为了保险起见,一定要保证有两个及以上可以启动的内核,以防止新编译的内核出现问题。例如:在使用grub的x86系统上,可以把arch/i386/boot/bzImage拷贝到/boot目录下,然后像vmlinuz-version一样命名它,并且编辑/etc/grub/grub.conf文件,为新内核建立一个新的启动项。

接下来以root身份,执行以下命令,就可以打完收工了:

#make modules_install

如果你对内核开发感兴趣,那么下面将要讲叙的内核开发特点对你至关重要。

五、内核开发特点

1、不能链接标准C库或者其它库

对于内核来说,C库太大且低效,大部分C库中的函数,内核中都有实现,基本的头文件都在内核源码树根目录的include目录下,而体系结构有关的头文件则位于arch//include/asm目录下,以x86体系结构为例,则体系结构相关的头文件位于arch/x86/include/asm目录下。

2、内核编程必须使用GNU C

Linux内核虽然是用C语言编写的,但是也有不按常理出牌的时候

88ac95b4f064824e9a160027d1e5599a.gif,其并不完全遵循ANSI C标准,它用到了gcc提供的许多语言的扩展部分,具体如下:

(1)内联(inline)函数。

为了降低函数调用和返回带来的开销采用内联函数。

(2)内联汇编。

为了提高效率混合使用C语言和汇编语言。

(3)分支声明。

对于条件选择语句,gcc内建了一条指令用于优化,即当一个条件经常出现或该条件很少出现的时候,编译器可以根据这条指令对条件分支选择进行优化,内核吧这条指令封装成了宏,比如:likely()和unlikely()。

3、没有内存保护机制

当应用程序试图进行一次非法的内存访问时,内核会报错(SIGSEGV),并结束整个进程。但是如果内核做了类似出格的事,它会神不知鬼不觉的闪人

a672d66dfdf9b696f8466d539140c2b8.gif。内核中的内存都不分页,即没用掉一个字节,物理内存就减少一个字节,内核真是个诚实的好孩子,一点都不偷奸耍滑

335eb2517a01c9845d21e86327cd7daf.png

4、难以执行浮点运算

在内核中使用浮点数时,除了要人工保存和恢复浮点寄存器,还有其它一些琐碎的事情要做。真够操劳的

5655027d4fbe664fba2129587101bf0e.gif

5、每个进程只有一个很小的定长堆栈

内核堆栈的准确大小随体系结构而变化,在x86上,堆栈大小在编译时配置,可以使4KB也可以是8KB,但是从历史上说,内核堆栈的大小是两页,也就是32位机的内核堆栈是8KB,而64位机是16KB,这是固定不变的,每个处理器都有自己的堆栈。

6、同步与并发陷阱

内核支持异步中断,抢占和SMP,以至于其很容易产生竞争条件,这就要求有同步机制以保证不出现竞争条件。常用的解决竞争的办法是自旋锁和信号量,具体请听后文书分解。

7、可移植性的重要性

Linux是一个可移植的操作系统,因此,大部分代码应该与体系结构无关,要做到这点就必须把体系结构相关代码分离出来,这个在前面就可见端倪。

本集结束,敬请期待下集。。。

524bbc790290d6bff1c59e86d5fe1a13.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值