内核编程语言和环境
- 语言编译过程就是把人类理解的高级语言转换成计算机硬件能理解和执行的二进制机器指令的过程。这种转换过程通常会产生一些效率不是很高的代码。所以一些对运行效率要求高或者性能影响较大的部分代码就会直接使用汇编语言来编写。或者对高级语言编译产生的汇编程序在进行人工修改或优化。
AS86汇编器
- Linux0.1x系统中使用了两种汇编器,一种是能产生16位代码的as86汇编器,使用配套的ld86链接器,另一种是GNU的汇编器gas(as),使用GNU ld链接器来链接产生的目标文件。
- 可以为80386处理器编制32位代码,但是linxu系统仅仅使用它们创建16位的启动引导扇区程序boot/bootsect.s和实模式下初始设置程序boot/setup.s的二进制执行代码。该编译器快速小巧,并具有一些GNU gas没有的特性,例如宏检查以及更多的错误检测手段,不过该编译器的语法与GNU as汇编编译器的语法不兼容。而更接近于微软的MASM、Borland公司的Turbo ASM和NASM等汇编器的语法,这些汇编器使用了Intel的汇编语言语法,操作数的次序与GNU as的相反。
as86汇编语言语法
- 汇编器专门用来吧低级汇编语言程序编译成含机器码的二进制程序或目标文件。汇编器会把输入的一个汇编语言程序编译成目标文件。
- 汇编的命令行基本格式为:
- as [选项] -o objfile srcfile
- 选项用来控制编译过程以产生指定格式和设置的目标文件。输入的汇编语言程序srcfile是一个文本文件。该文件内容必须是由换行符结尾的一系列文本行组成。
- 语句可以是只包含空格、制表符和换行符的空行,也可以是赋值语句、微操作符语句和机器指令语句。赋值语句用于给一个符号或标识符赋值,他由标识符后跟一个等于号,在根一个表达式组成,如“BOOTSEG=0X07C0”,伪操作符语句是汇编器使用的指示符,通常并不产生任何代码。他由微操作码和0个或多个操作数组成,每个操作码都由一个点字符“.”开始,点字符“.”本身是一个特殊的符号,他表示编译过程中的位置计数器,其值是点符号出现处机器指令第一个字节的地址。
- 汇编器编译产生的目标文件objfile通常至少包含三个段或区,即正文段(.text)、数据段(.data)和未初始化数据段(.bss)。
- 机器指令语句是可执行机器指令的助记符,由操作码和0个或多个操作数构成。另外任何语句之前都可以有标号,标号是由一个标识符后跟一个冒号“:”组成。在编译过程中。当汇编器遇到一个标号,那么当前位置计数器的值就会复制给这个标号,因此一条汇编语句通常由标号、指令助记符和操作数三个字段组成,标号位于一条指令的第一个字段。他代表其所在位置的地址,通常指令一个跳转指令的目标位置,最后还可以跟随用注释符。
- 汇编器编译产生的目标文件objfile通常包括至少包含三个段或区,即正文段(.text)、数据段(.data)和未初始化数据段(.bss)。正文段是一个已初始化过的段,通常其中包含程序的执行代码和只读数据。数据段也是一个已初始化过的段,其中包含可读、写的数据,而未初始化的数据段是一个未初始化的段。通常汇编器产生的输出目标稳健中不会为该段保留空间,但在目标文件链接成可执行程序被加载时操作系统会把该段的内容全部初始化为0.汇编语言程序中会产生代码或数据的语句,都会在这三个中的一个段生成代码或数据。编译产生的字节会从“.text”段开始存放,可以使用段控制伪操作符来更改写入的段。
AS86汇编语言程序
- 下面是一个简单的boot.s说明as86汇编程序的结构以及程序中语句的语法,然后给出编译链接和运行方法,最后分别使用as86和ld86的使用方法和编制选项。
!
!boot.S --bootsect.s 的框架程序,用代码0x07替换串msg1中1字符,然后在屏幕上显示
!
.globl begtext,begdata,begbss,endtext,enddata,endbss !全局标识符,供ld86链接使用。
.text !正文段
begtext:
.data
begdata:
.bss
begbss:
.text
BOOTSEC=0X07C0
entry start
start:
jmpi go,BOOTSEC !段间跳转 BOOTSEC 指出跳转地址 标号go是偏移地址
go: mov ax,cs
mov ds,ax
mov es,ax
mov [msg1+17],ah !0x07 --->替换字符中一个点符号 喇叭会鸣一声
mov cx,#20 !共显示20个字符
mov dx,#0x1004 !字符显示在屏幕第17行、第五列处
mov bx,#0x000c !字符显示属性 (红色)
mov bp,#msg1 !指向要显示的字符
mov ax,#0x1301 !写字符串并移动光标到串结尾处
int 0x10
loop0: jmp loop0 !死循环
msg1: .ascii "Loading system...!" !调用BIOS中断显示的 信息
.byte 13,10
.org 510 !表示以后语句从地址510(0x1fe)开始存放
.word 0xAA55 !有效引导扇区标志,提BIOS加载引导扇区
.text
endtext:
.data
enddata:
.bss
endbss:
- 上面示例是bootsect.S的一个框架程序,能编译生成引导扇区代码。编译链接产生的执行程序可以放入软盘第一个扇区来引导计算机启动,启动后会在屏幕第17行第五列处显示出红色字符串“Loading system”,并且光标下移一行。
- as86汇编程序中,以感叹号“!”或分号“:”开始的语句其后面为注释文字。
- .globl为汇编指示符,以一个字符“.”开始,并不会在编译时产生任何代码。汇编指示符由一个伪操作码,后跟0个或多个操作数组成.
- BOOTSEG=0x07c0,等号用于定义标识符BOOTSEG所代表的值,因此这个标识符可称为符号常量。
- entry为保留关键字,用于使ld86在生成的可执行文件中包括进其后指定的标号start,通常在链接多个目标文件生成一个可执行文件时应该在其中一个汇编程序中用关键字entry指定一个入口标号以便于调试。
- BLOS将程序加载到物理内存0x7c00,并跳转到该处时所有寄存器默认为0,此时CS:IP=0X000:0X7c00,这里使用段间跳转语句就是为了给CS赋值段值0x7c0,该语句执行后CS:IP=0X7C0:0X0005,随后的两条语句分别给DS和ES段寄存器赋值,让他们都指向0x7c0段,这样便于对程序中的数据进行寻址。
as86 -0 -a -o boots.o boots.s
ld86 -0 -s -o boot boots.o
dd bs=32 if=boot of=../Linux-0.12-master/Kernel_Image skip=1
- 第一条命令利用as86汇编器对boot.s程序进行编译,生成boot.o目标文件。使用链接器ld86对目标文件执行链接操作,生成MINIX结构的可执行文件boot。-0用于生成8086的16位目标程序,-a用于指定生成与GNU as和ld部分兼容代码,-s告诉链接器去除可执行文件的符号信息。
- 使用dd删除boot程序前32B,并将结果写入Linux-0.12-master/Kernel_Image
qemu-system-x86_64 -m 16 -boot a -fda Linux-0.12-master/Kernel_Image -hda hdc-0.11.img -s