Linux 内核学习笔记系列,内核开发部分,简单介绍 Linux 内核体系结构和可移植性相关的内容。

体系结构相关的源码目录

为了便于扩展到新的体系结构,内核严格隔离了与体系结构相关和无关的代码。

在较早的版本中,与体系结构 T 相关的 C 和汇编源码位于 arch/T 目录下,头文件则位于 include/asm-T。后来,体系结构相关的头文件挪到了 arch/T/include/asm 下。

本系列学习笔记主要基于 Linux 2.6.34 版本,且仅针对 x86 体系结构,所以对于体系结构相关的代码,我只关心 arch/x86 目录。

字长

字长是指机器一次能完成处理的数据。处理器的通用寄存器的大小应该和它的字长是一致的。

对于 x86 处理器,有 32 位(i386)和 64 位(x86-64)的版本,出于历史原因和某些主观的命名习惯,我们根据长度来划分数据,长度的单位是位(bit):

名称长度
字节(byte)8
字(word)16
双字(double word)32
四字(quad word)64

在 Linux 中,一个字通常代表处理器的字长。对于 32 位的 i386,字长是 32 位(4 字节);对于 64 位的 x86-64,字长是 64 位(8 字节)。

具体“字”的含义,要根据上下文来确定。

数据类型

C 标准并未明确指定数据类型的数据长度,在不同的平台下,这些数据类型的长度可能不同。我不准备在这里讨论 C 标准的具体内容。

把内核中的数据类型归为以下几类:

  • 不透明类型:如进程标识符 pid_t,通常情况下直接使用即可,可以把这些类型视为黑盒。
  • 指定长度的类型:如 flag 参数应当使用 unsigned long(这样能确保该变量在 32 位和 64 位情况下长度一样),可以理解为人为的约定。
  • 长度明确的类型:如 s8 代表有符号 8 位整数,u16 代表 16 位无符号整数,等等。

特别地,对于 char 类型,默认是带符号的还是不带符号的,在不同环境下可能不同。如果需要指明,可以显示声明为 signed charunsigned char。否则使用的时候应该多加小心。

数据对齐

数据对齐通常指把数据放置到其字节长度可以整除的字节地址,即对于一个大小为 2^n 字节的数据类型,它的地址最低有效位的后 n 位应当为 0。

现在的编译器会自动完成数据对齐的工作,对于普通程序员,小心使用指针强制类型转换后引起的对齐问题即可,比如:

1
2
3
char wolf[] = "Like a wolf";
char *p = &wolf[1];
unsigned long l = *(unsigned long *)p;

这里 l 试图解引用一个非对齐的数据。

对于复合数据类型,它们的对齐标准如下:

  • 数组:按基本数据类型进行对齐,这样所有的元素都能对齐。
  • 联合体:按包含的最长的数据类型进行对齐。
  • 结构体:结构体中每个元素都正确对齐。

特别地,对于结构体,为了使每个元素都正确对齐,有时需要填补,比如:

1
2
3
4
5
6
struct animal {
    char dog;           /* 1字节 */
    unsigned long cat;  /* 4字节 */
    unsigned short pig; /* 2字节 */
    char fox;           /* 1字节 */
};

该结构体被填补后相当于下面的结构体:

1
2
3
4
5
6
7
8
struct animal {
    char dog;           /* 1字节 */
    u8 __pad0[3];       /* 3字节 */
    unsigned long cat;  /* 4字节 */
    unsigned short pig; /* 2字节 */
    char fox;           /* 1字节 */
    u8 __pad1;          /* 1字节 */
};

字节顺序

字节顺序分高位优先(大端机,big-endian)和低位优先(小端机,little-endian)。

高位优先即数据的低位到高位对应内存地址的高位到低位,低位优先即数据的低位到高位对应内存地址的低位到高位。

以存储数据 0x1 为例,高位优先和低位优先的存储方式如下:

1
2
3
4
5
6
二进制位:0 1 2 3
二进制值:0 0 0 1

内存地址:0 1 2 3
高位优先:0 0 0 1
低位优先:1 0 0 0

不同处理器的字节顺序可能不同,对于 x86 体系结构,使用的都是低位优先的字节顺序。

其他体系结构相关的内容

还有很多内容和体系结构相关,包括时间、页、内存分布、系统调用、处理器排序等等,这些内容不再展开,其中部分内容会在后续的学习笔记涉及。