《Linux内核完全注释》(3)

关于博客:当公开学习笔记写,如果对于有感想的地方就发散一下,没有感想的地方就了解学习一下。总之这个笔记不能代替书,也不是那种总结手册,更像是学习日记,请各位朋友理解。

3.4 C与汇编程序相互调用

在 Linux 内核程序 boot/head.s 执行完基本初始化操作之后,就会跳转去执行 init/main.c 程序。

3.4.1 栈帧结构与控制转移权方式

大多数 CPU 上的程序实现使用栈来支持函数调用操作。栈被用来传递函数参数、存储返回信息、临时保存寄存器原有值以备恢复以及用来存储局部数据。通过栈先入后出的特性,使函数可以实现嵌套。push和pop用于将数据压入栈或者从栈中弹出。CALL和RET用于处理函数调用和返回。在调用函数前,栈中保存的是现在所在函数的局部变量,调用函数后,先会在栈中压入一个运行完调用函数后的返回地址,再保存被调用函数的ebp(帧指针,栈底指针)和局部变量等信息。

GCC有时不能生成最高效率的代码,所以某些关键代码需要直接使用汇编语言编制。

3.4.2 在汇编程序中调用C函数

在汇编程序调用一个 C 函数时,程序需要首先按照逆向顺序把函数参数压入栈中,即函数最后(最右边的)一个参数先入栈,而最左边的第 1 个参数在最后调用指令之前入栈。然后执行CALL指令去执行被调用的函数。在调用函数返回后,程序需要再把先前压入栈中的函数参数清除掉。

3.4.3 在C中调用汇编程序

如果汇编比较短,可以直接使用内联汇编的方式来解决。如果程序较长的,其调用方法与在汇编中调用C语言的原理相同,但在内核程序中较少使用。

3.5 Linux0.12目标文件格式

为便于描述,这里把编译器生成的目标文件称为目标模块文件(简称模块文件),而把链接程序输出产生的可执行目标文件称为可执行文件。并且把它们都统称为目标文件。

a.out 格式文件由一个文件头和随后的代码区( Text section,也称为正文段)、已初始化数据区( Data section,也称为数据段)、重定位信息区、符号表以及符号名字符串构成。
执行头部分:
struct exec {
unsigned long a_magic // 执行文件魔数。使用 N_MAGIC 等宏访问。
unsigned a_text // 代码长度,字节数。
unsigned a_data // 数据长度,字节数。
unsigned a_bss // 文件中的未初始化数据区长度,字节数。
unsigned a_syms // 文件中的符号表长度,字节数。
unsigned a_entry // 执行开始地址。
unsigned a_trsize // 代码重定位信息长度,字节数。
unsigned a_drsize // 数据重定位信息长度,字节数。
}

重定位信息部分:
struct relocation_info
{
int r_address; // 段内需要重定位的地址。
unsigned int r_symbolnum:24; // 含义与 r_extern 有关。指定符号表中一个符号或者一个段。
unsigned int r_pcrel:1; // 1 比特。 PC 相关标志。
unsigned int r_length:2; // 2 比特。指定要被重定位字段长度( 2 的次方)。
unsigned int r_extern:1; // 外部标志位。 1 - 以符号的值重定位。 0 - 以段的地址重定位。
unsigned int r_pad:4; // 没有使用的 4 个比特位,但最好将它们复位掉。
};

符号表和字符串部分
struct nlist {
union {
char *n_name; // 字符串指针,
struct nlist *n_next; // 或者是指向另一个符号项结构的指针,
long n_strx; // 或者是符号名称在字符串表中的字节偏移值。
} n_un;
unsigned char n_type; // 该字节分成 3 个字段,参见 a.out.h 文件 146-154 行。
char n_other; // 通常不用。
short n_desc; //
unsigned long n_value; // 符号的值。
};

a.out执行文件映射到进程逻辑地址空间:

3.5.3 链接程序输出

链接程序对输入的一个或多个模块文件以及相关的库函数模块进行处理,最终生成相应的二进制执行文件或者是一个所有模块组合而成的大模块文件。

这张图非常形象地解释了链接所做的事情,链接就是按段分配空间,将小模块的各部分合起来,再拼起来搓成大模块。

3.6 Make和Makefile文件

一个 Makefile 文件可以包括五种元素:显式规则、隐含规则、变量定义、指示符和注释信息。

显式规则( explicit rules)用于指定何时以及怎样重新编译一个或多个被称作规则的目标( rule’s targets)的文件。规则中明确列出了目标所依赖的被称为目标的先决条件(或依赖)的其他文件,同时也会给出用于创建或更新目标的命令。
隐含规则( implicit rules)则是根据目标和对象的名称来确定何时和如何重新编译一个或多个被称作规则的目标的文件。这种规则描述了目标是如何依赖于与目标名称相类似的文件,并会给出用于创建或更新这样的一个目标文件。
变量定义( variable definitions)用于在一行上为一个变量定义一个文本字符串。该变量可在后续语句中被替换。例如后面例子中的变量 objects 定义了所有.o 文件的列表。
指示符( directives)是 make 的一个命令,用于指示其在读取 Makefile 文件时执行的特定操作。这些操作可包括读取另一个 makefile 文件;确定使用或忽略 makefile 文件的某部分内容和从包含多行的字符串中定义一个变量。

具体的makefile相关教程可以查询其他资料,本书只是简单介绍,后面看懂即可。

热门相关:万古第一帝   甜蜜隐婚:老公大人,宠上瘾   名门贵妻:暴君小心点   貌似纯洁   甜蜜隐婚:老公大人,宠上瘾