我们使用Eclipse创建一个C语言的Mailfile工程,并创建一个名为boot.S的文件,这个文件就是我们需要使用AT&T汇编语言编写的操作系统引导程序。这个程序非常简单,代码如下:
#ifndef _BOOT_S_ #define _BOOT_S_
如果没有定义_BOOT_S_标识符,则定义_BOOT_S_,这是一个典型的C语言风格的条件编译处理,目的是为了防止在多个文件相互整体编译时出现的代码定义重复。这里虽然只有一个boot.S文件,但是我们要从一开始就养成良好的编程习惯,所以也要这样定义。
//16位操作数和16位寻址模式 .code16
我们要在一个32位或64位操作系统的编译环境下编译出一个16位的程序,这样在处理实时模式的CPU才可以识别这样的程序。对于.code16就是定义一个16位操作标识,告诉gcc编译器,我们这个程序从此处开始采用的是16位操作数和16位寻址模式。
//全局过程名 .global _start
告诉gcc这里有一个叫作_start的过程(也可以理解为C语言的函数),它是一个全局过程,也就是一个外部连接过程。定义一个全局外部过程的目的就是在使用ld命令做链接时需要用到它,这个下面会继续说明。
//数据段 .section .data
.section .data代表的是数据段开始。
//代码段 .section .text
.section .text代表的是代码段开始。
//开始 _start: jmp _start
_start:就是定义过程开始的过程名称,jmp start就是当程序执行到这里时,无条件的跳转到_start处,也就是说这里是一个死循环。
//占位,从此行开始到0x1fe止匀为0x90也就是nop .org 0x1fe, 0x90
//以0xaa55结束 .word 0xaa55
#endif
#endif结束第一行的#ifndef _BOOT_S_条件编译。
接下来我们需要将这段汇编代码编译成一个二进制的可执行程序。我们的工程是一个Makefile工程,通过Makefile我们可以灵活的使用gcc、ld、objcop、dd等有用的命令。下面我们来一起看一下Makefile的内容:
BUILD = build定义一个变量BUILD,它的值是build,因为我们想用它来作为编译结果的输出目录。
all: mkdir -p $(BUILD)
执行Linux的mkdir命令创建一个名为build的文件夹。
gcc boot.S -c -m32 -std=c99 -o $(BUILD)/boot.o使用gcc编译boot.S文件,并使用32位编译模式和c99标准。
ld -m elf_i386 -Ttext 0x0 -e _start $(BUILD)/boot.o -o $(BUILD)/boot
链接boot.o文件,并使用_start过程为程序的入口,这个_start就是我们在boot.S中定义的全局过程名。
objcopy -O binary $(BUILD)/boot $(BUILD)/boot.bin
将boot.o文件转为纯二进制文件boot.bin。
dd bs=512 count=2880 if=/dev/zero of=$(BUILD)/boot.img
使用dd命令生成一个boot.img软盘镜像文件,每个块(扇区)大小为512字节,一共有2 * 80 * 18 = 2880个块(2个柱面 * 80个磁道 * 18个扇区)。
dd bs=512 count=1 conv=notrunc if=$(BUILD)/boot.bin of=$(BUILD)/boot.img将boot.bin这个纯二进制可执行程序烧录到img软盘镜像文件的第1个扇区中。
clean: rm -rvf $(BUILD)
clean为Makefile中一个标识符,意思为清空。在这里是执行rm命令,删除build文件夹。在Eclipse里执行build project命令,或者使用Linux命令在我们的lidqos工程目录下执行make all命令就可以按Makefile的方式进行编译了。
make all mkdir -p build gcc boot.S -c -m32 -std=c99 -o build/boot.o ld -m elf_i386 -Ttext 0x0 -e _start build/boot.o -o build/boot objcopy -O binary build/boot build/boot.bin dd bs=512 count=2880 if=/dev/zero of=build/boot.img dd bs=512 count=1 conv=notrunc if=build/boot.bin of=build/boot.img 2880+0 records in 2880+0 records out 1474560 bytes (1.5 MB) copied, 0.148839 s, 9.9 MB/s 1+0 records in 1+0 records out 512 bytes (512 B) copied, 0.00113384 s, 452 kB/s 17:17:09 Build Finished (took 534ms)
编译成功之后在我们的工程目录下就会生成boot.o、boot、boot.bin、boot.img等文件,如下图所示:
这样,我们就有了一个可以“引导”计算机的操作系统程序,虽然这个程序什么功能都没有,只有一个死循环,但毕竟在启动计算机时就可以让BIOS程序找到它,并且不再会出现类似“Could not read from the boot mediaum!”的错误了。
使用VirtualBox创建一个名为lidqos的虚拟机,为其添加一个软盘控制器Floppy,并为其分配我们刚刚生成的boot.img文件的全路径。如下图:
点击OK按钮之后,启动lidqos虚拟机,就可以看到我们的操作系统了。如下图所示:
运程的效果是我们预期的,因为我们的操作系统始终在执行那个永无休止的循环。
源代码的下载地址为:
https https://github.com/magicworldos/lidqos.git git git@github.com:magicworldos/lidqos.git subverion https://github.com/magicworldos/lidqos branch v0.1
Copyright © 2015-2023 问渠网 辽ICP备15013245号