LINUX 0.11内核完全剖析学习笔记-第三章内核编程语言和环境

一.编译器

       linux 0.11 集成了两种汇编器。一种是能产生16位代码的as86汇编器,使用配套的ld86链接器;另一种是GUN汇编器gas,使用GNU ld链接器俩链接产生的目标文件。

1.1 as86汇编器

       as86和ld86虽然可以编制32位代码,但在linux下用它来创建16位的启动引导扇区程序boot/bootsect.S和是模式下初始设置程序boot/setup.s的二进制执行代码。其语法结构如下:

       as[选项] -o objfile srcfile  (把srcfile文件编译成目标文件objfile)。

       选项用来控制编译过程以产生指定格式和设置的目标文件,汇编器产生的目标文件objfile通常包括至少3个段或者区。即正文段,数据段和未初始化数据段,正文段是已经初始化过的段通常包括程序的执行代码和只读数据;数据段也是初始化过的段,其中包含可读/写的数据。

      as的用法和ld的用法如下:LINUX 0.11内核完全剖析学习笔记-第三章内核编程语言和环境_第1张图片LINUX 0.11内核完全剖析学习笔记-第三章内核编程语言和环境_第2张图片


LINUX 0.11内核完全剖析学习笔记-第三章内核编程语言和环境_第3张图片

1.2 GNU as汇编器

     内核中除了boot/bootsec.s引导扇区程序和实模式下的设置程序boot/setup.s,其余所有汇编程序都是用gas来编译生成。汇编器的命令格式与上面的相同。

    as[选项] -o objfile [srcfile.S ...] 

       如果没有使用编译输出的目标文件,那么as会编译输出名称为a.out的默认目标文件。as汇编器具有对汇编语言程序内置的简单预处理功能。预处理功能会调整并删除多余的空格字符和制表符。改处理功能不会对宏定义进行处理,也没有处理包含文件的能力。

       指令是CPU执行的操作,通常也叫操作码,操作数就是指令操作的对象。地址是制定数据在内存中的位置。指令语句是程序运行时刻执行的一条语句,它通常包括4个部分:

      标号,操作码,操作数,注释。

      区与重定位:

      区用于表示一个地址范围,操作系统会以相同的方式对待和处理在该地址范围中的数据信息。链接器ld会把输入的目标文件中的内容按照一定规律生成一个可执行程序。当as汇编器输出一个目标文件时,该目标文件中的代码被默认设置成重地址0开始,ld将会在链接过程中为不同目标文件中的各个部分分配不同的最终地址位置。当涉及到一个区被重定位时,为了执行重定位操作,每次涉及目标文件中的一个地址,ld必须知道:

      1. 目标文件中对一个地址的引用从什么地方开始计算?

      2.引用的字节长度是多少?

      3.该地址是作用于哪个区?

      4.对地址的引用于指令计数器PC相关吗?

二. C语言

      使用GCC汇编器编译c语言通常经过4个阶段:预处理,编译,汇编,链接。预处理阶段gcc把C程序传递给C前处理器cpp,对C语言中的宏和指示符进行替换处理,输出纯C代码;在编译阶段,gcc把C语言程序编译生成对应的与机器相关的as汇编语言代码;在汇编阶段,as汇编器把汇编代码转换成机器指令,并以特定的二进制格式输出保存在目标文件中;最后ld链接器把程序的相关目标文件组合链接在一起。为了提高效率有时我们会在c代码中嵌入汇编语言,这长用于对于寄存器的直接操作中,嵌入式汇编的格式如下:

       asm("汇编语句"

              :输出寄存器

               :输入寄存器

               :会被修改的寄存器);

三.目标文件的格式

LINUX 0.11内核完全剖析学习笔记-第三章内核编程语言和环境_第4张图片

a.out 格式7个区的基本定义和用途:

      执行头部分,该部分含有一些参数是有关目标文件的整体结构信息

       代码区,由编译器和汇编器生成的二进制代码和数据

       数据区,由编译器和汇编器生成的二进制代码和数据

      代码重定位,这部分含有链接程序使用的数据,当链接程序需要改变目标代码的地址时需要修正的地方

      符号表示部分,这些地方记录着模块文件中定义的全局符号以及需要从其他模块文件中输入的符号

      字符串表示部分,这部分含有有符号名相对应的字符串,仅供调试代码使用,与链接器没有关系

     在执行头部分文件结构中魔术字段值把文件分成两种类型。一种是模块文件OMAGIC(其魔术值为0x107),另外一种是ZMAGIC类型文件(其魔术值为0x10b),两者区别在于一个OMAGIC类型文件在文件开始部分32B后就是数据区和代码区,而另外一种文件开始部分需要有1KB空间,而除去32B的头外其余数据都为0.

      查看文件头文件信息使用objdump -h,可以看到文件的魔术值,以及代码段数据段的总体信息。查看文件的内容使用hexdump,对于文件来说可能上述的7个部分不是必须的,那么在链接器生成了代码后我们还可以使用strip去掉某些我们没有必要使用的段。


四.Makefile

     对于Makefile文件,看过内核文件的都应该不陌生,无论是在根目录下还是在每级子目录下都会有这个文件。这个文件的作用就是能够解决编译多个文件的问题。举个例子说明:假如我们有hello.c这样的一个文件,那么我们生成目标文件只需要直接使用gcc生成目标文件即可,但是如果文件很多又存在相互关联的问题,那我们就需要使用Makefile文件了。

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

显式规则(explicit rules)用于指定何时以及怎样重新编译一个或多个被称作规则的目标(rule's targets)的文件。规则中明确列出了目标所依赖的被称为目标的先决条件(或依赖)的其他文件,同时也会给出用于创建或更新目标的命令。

隐含规则(implicit rules)则是根据目标和对象的名称来确定何时和如何重新编译一个或多个被称作规则的目标的文件。这种规则描述了目标是如何依赖于与目标名称相类似的文件,并会给出用于创建或更新这样的一个目标文件。

变量定义(variable definitions)用于在一行上为一个变量定义一个文本字符串。该变量可在后续语句中被替换。例如后面例子中的变量objects定义了所有.o文件的列表。

指示符(directives)是make的一个命令,用于指示其在读取Makefile文件时执行的特定操作。这些操作可包括读取另一个makefile文件;确定使用或忽略makefile文件的某部分内容和从包含多行的字符串中定义一个变量。

注释(comments)是指Makefile文件中以"#"字符开始的文字部分。如果确实需要使用"#"字符,我们需要对其进行转义,即在该字符前添加一个反斜杠字符("\#")。注释可以出现在Makefile文件的任何地方。另外,Makefile文件中以制表符TAB开始的一行命令脚本会被完整地被传递给shell,shell会判断这是一条命令还是只是一个注释信息。

      Makefile文件的表现形式主要如下:

target(目标)…:prerequisites(先决条件)…
command(命令)


其中,target(目标)对象通常是指程序生成的一个文件的名称,例如它可以是一个可执行文件或者是一个以".o"结尾的目标文件(Object File)。目标也可以是所要采取活动的名称,例如"清理"("clean")。这里请注意,由于"target"和"object file"中的"object"通常都被译成中文的"目标",因此为了区别,我们把"target"译作"目标"或直接用其英文,而把object file译为".o文件"。

prerequisite(先决条件或称依赖对象)是用以创建target所必要或者依赖的一系列文件或其他目标。target通常依赖于多个这样的必要文件或目标文件。

command(命令)是指make所执行的操作,通常就是一些shell命令,是生成target需要执行的操作。当先决条件中一个或多个文件的最后修改时间比target文件的要新时,规则的命令就会被执行。另外,一个规则中可以有多个命令,每个命令占用规则中单独一行。请注意,我们需要在写每个命令之前键入一个制表符(按Tab键产生)!

     

    



你可能感兴趣的:(linux内核笔记,linux0.11,读书笔记,linux内核)