1、本章主要描述Linux 0.12内核中使用的汇编语言、目标文件格式和编译环境,主要目标是提供阅读Linux 0.12内核源代码所需要的汇编语言和GNU C语言扩展知识。
首先,比较详细地介绍了as86和GNU as汇编程序的语法和使用方法;
然后,对GNU C语言中的内联汇编、语句表达式、寄存器变量以及内联函数等内核源代码中常用的C语言扩展内容进行介绍。
同时,详细描述了C和汇编函数之间的相互调用机制。
之后,理解目标文件格式,是了解汇编器如何工作的重要前提之一。
稍后,详细给出Linux0.12系统中使用的a.out目标文件格式。
最后,简单描述Makefile文件的使用方法。
2、Linux 0.1x系统中使用了两种汇编器:as86汇编器+ld86链接器 (主要编译16位的启动引导扇区程序和初始设置程序); GUN as汇编 + GNU ld链接器 。
看着想睡有没有,只有看到汇编再回来查了。
3、C语言程序
GNU gcc对ISO标准C89描述的C语言进行了一些扩展,其中一些扩展部分已经包括进ISO c99标准中。
使用gcc汇编器编译C语言程序时通常会经过4个处理阶段,即预处理阶段、编译阶段、汇编阶段和链接阶段。
内联汇编基本格式:
asm("汇编语句"
:输出寄存器
:输入寄存器
:会被修改的寄存器);
GUN C对C语言的两一个扩充是允许我们把一些变量值放到CPU寄存器中,即所谓寄存器变量。分全局和局部寄存器变量。Linux中只是用了局部寄存器变量,定义方法:
register int res __asm__("ax");
内联函数(inline):gcc可以直接将函数的代码集成到调用该函数的代码中去,这样可以去掉调用它的进入退出时间开销,从而加快执行速度。内联函数嵌入调用者代码中的操作是一种优化操作,因此只有进行优化编译时才会执行代码嵌入处理。若编译过程中没有使用优化选项“-O”,那么内联函数的代码就会只作为普通函数调用来处理。内联函数的应用格式: (-Winline)
inline int inc(int *a)
{
(*a)++;
}
内联函数 extern inline组合在一起的作用几乎类同一个宏定义。
4、C与汇编程序的互相调用
C函数调用机制: 通过栈操作数据传递和局部变量存储。 指令CALL和RET用于处理函数调用和返回操作;调用指令CALL的作用是把返回地址压入栈中并且跳转到被调用函数开始处执行。返回地址是程序中紧随调用指令CALL后面一条指令的地址。
手动链接顺序:crtl.o crti.o crtbegin.o 所有程序模块 crtend.o crtn.o 库模块文件。。其中crtl crti crtn由C库提供,是其启动模块;crtbegin crtend是C++语言启动模块。
汇编中调用C函数:在汇编程序调用一个C函数时,程序需要首先按逆向顺序把函数参数压入栈中,即函数最后一个参数先入栈,而第一个参数在最后调用指令之前入栈。然后执行CALL指令去执行被调用的函数。在调用函数返回后,程序需要再把先前压入栈中的函数参数清除掉。
C中调用汇编函数: 原理与上相同,但是Linux内核中不常用,调用方法的着重点是对函数参数在栈中位置的确定上。如果较短可以使用汇编内联语句来实现。
5、Linux 0.12目标文件格式 结构及链接器如何工作的。
目标文件由以下部分顺序构成: a.out文件头、代码部分、数据部分、代码重定位信息、数据重定位信息、符号表、字符串表。
链接程序对输入的一个或多个模块文件以及相关的库函数模块进行处理,最终生成相应的二进制执行文件或一个由模块组合而成的大模块文件。这个过程中,链接程序首先给执行文件分配存储空间,然后将所有模块中相同类型的段组合连接在一起,在输出文件中为指定段类型形成单一一个段。
内核作为一个执行程序有build工具去掉各个模块的头结构,然后将各个它们的各个段顺序组合在一起生成内核影响文件。 引导启动程序就可以利用ROM BIOS中断调用加载内核到内存中执行。
gld -M 或者nm命令,可以链接时在标准输出上打印出链接映像信息。其中列出了程序段装入到内存中的位置信息。通常会重定向到一个文件中,例如 System.map。利用这个符号表文件,在内核或相关程序出错时,可以我们比较容易识别的信息。 这样我们就可以非常方便的对内核进行调试了。
6、Make程序和Makefile文件 可以参考《跟我一步一步写Makefile》