第二章 Linux开发准备

1. 获取源码

获取Linux的源码常见方式:
https://github.com/torvalds/linux
https://www.kernel.org/
https://mirrors.tuna.tsinghua.edu.cn/ 清华大学
https://mirrors.aliyun.com/ 阿里云

2. 源码目录结构

在线查看:http://lxr.free-electrons.com/ 没有好的2.6版本的在线查看地址,还是下载源码用Source Insight工具查看方便。

内核源码一般在/usr/src/linux目录

目录 说明
Documentation/ 文档
arch/ 特点体系结构代码
block/ 块设备I/O
certs/ 证书
crypto/ 加密API
drivers/ 设备驱动程序
firmware/ 某些设备固件
fs/ VFS和各种文件系统
include/ 内核头文件
init/ 内核引导和初始化
ipc/ 进程间通信代码
kernel/ 核心子系统
lib/ 通用内核函数
mm/ 内存管理子系统和VM
net/ 网络子系统
samples/ 示例代码
scripts/ 编译内核所用脚本
security/ Linux安全模块
sound/ 语音子系统
tools/ 开发工具
usr/ 早期用户空间代码(initramfs)
virt/ 虚拟化基础结构
COPYING copyright
CREDITS 核心开发者列表
Kbuild
Kconfig
MAINTAINERS 维护者列表
Makefile for make
  • 打补丁: patch -pl < ../patch-x.y.z

3. 编译内核

Linux内核编译支持配置和定制,可以按需选取特定功能和驱动程序编译进内核,其他模块可以以内核模块的形式动态加载。

配置选项以CONFIG_FEATURE的形式表示,要么二选一:yes or no,要么三选一:yes、no or module,module即表示以内核模块的方式编译相关代码,驱动程序一般为三选一。

配置命令:

  • make config
  • make menuconfig **
  • make gconfig
  • make defconfig - 生成默认配置
  • make oldconfig - 用已有配置文件进行配置
    配置项最终会放在内核代码树根目录下的.config文件中
1
2
3
4
5
zcat /proc/config.gz > .config
make oldconfig
make
# make -j32 > /dev/null 并行编译

4. 内核开发的特点

linux kernel C语言规范:
中文版
英文版

4.1 无标准C函数库

常用C库都有内核版本的实现,基本头文件位于内核源码树include目录,体系结构相关头文件位于内核源码树的arch//include/asm目录下,内核代码以asm/xxx.h的形式包含这些头文件。

4.2 使用GNU C

内核使用的C语言涵盖了ISO C99标准和GNU C扩展特性

  • 内联(inline)函数

    • 内联函数在编译时会在它被调用的位置上展开,消除函数调用和返回所带来的开销,也利于编译器优化,性能较好。但是,内联函数会使代码变长,占用更多的内存或指令缓存。
    • 例子: static inline void foo()
    • 内联函数必须在使用之前定义好,通常在头文件中定义。
  • 内联汇编
    在偏近体系结构底层或对执行时间要求严格的地方,使用汇编语言

  • 分支声明
    gcc内建了一条指令判断一个if语句时经常为真还是经常为假,内核封装成宏likely()和unlikely()

  • 没有内存保护机制
    内核发生内存错误会导致oops,系统会挂掉;内核的内存都不分页,没用掉一个字节,物理内存就少一个字节,因此内核使用内存要谨慎

  • 不要使用浮点数
    内核不能完美支持浮点操作,因为它本身不能陷入,使用浮点数时,除了要人工保存和恢复浮点寄存器还要其他一些繁琐的操作。

  • 容积小而固定的栈
    内核的栈大小在编译时进行配置,之后固定不变,每个处理器都有自己的栈。不同的体系结构,栈的大小可能不同,但都不大

  • 同步和并发
    Linux是多用户操作系统,内核支持异步中断、抢占和SMP,容易产生race condition,必须时刻考虑并发

  • 可移植性
    Linux作为一个可移植的操作系统,在开发时要将与体系结构相关代码分离