[reprint]如何编写引导程序 Hello World
在存储介质(硬盘、软盘、光盘)中有一块特殊的区域,叫做引导区。在计算机启动后,BIOS会读取引导区内的代码到内存中去,然后将执行这些代码。引导区的位置和大小与计算机的平台有关,对于IBM-PC兼容机,引导区位于存储介质的第一个扇区,大小为512字节。位于引导区内的代码就称为引导程序。引导区内是否含有引导程序由引导区内的标记标识。对于IBM-PC兼容机,如果引导区内的最后两个字节为0x55,0xAA,则BIOS检测程序认为引导区内包含引导程序。引导程序并不一定要实现加载操作的功能,它可以是任何程序。
IBM-PC兼容机的具体启动过程如下:
1.按下计算机的电源键后,x86 CPU就开始在实模式下运行位于物理地址0xFFFFFFF0(通常这个地址是指向的是位于ROM中的BIOS的入口点)处的指令,这个指令是一个跳转指令,跳转到BIOS的启动程序。启动程序运行硬件检测和初始化操作。
2.在初始化所需要的硬件后,BIOS就依据设定的启动顺序遍历存储设备,直到找到一个可引导的设备。一个可引导的存储设备是引导区内包含引导程序。BIOS通过检查引导区的最后两个字节是否为0x55,0xAA来判断引导区内是否包含引导程序。
3.一旦BIOS找到了可引导的设备,它就加载引导区代码到内存物理地址的0x7C00(通常是Segment:Offset 0000h:7C00h,也有些BIOS为07C0h:0000h),之后BIOS将控制权交给引导程序,CPU开始执行引导程序,引导程序开始加载操作系统内核或者其他。
在格式化硬盘安装好Windows后,硬盘第一个扇区(引导区)包含MBR引导代码,BIOS在加载MBR代码后,MBR开始检查硬盘中是否存在活动分区(含引导程序的分区),如果存在活动分区,则加载位于那个分区的引导程序(通常称为VBR,与操作系统相关),然后执行它。VBR的主要功能是加载操作系统的内核。
了解了相关知识,我们如何编写一个打印Hello World的引导程序呢?
需要准备的工具:
文本编辑软件、MASM编译器(我采用的是VS2008自带的ML 9.0)、16位Link程序、VMWare、PE(用于格式化VMWare创建的虚拟磁盘)、NtExplorer
具体步骤:
1. 打开你习惯使用的文本编辑器,编写下面代码。因为BIOS会将我们的引导程序加载到内存地址的7C00h处,所以我们需要org指令设置我们代码指令的地址值。

;------------------------------------------------------------
.286 ; CPU type
;------------------------------------------------------------
.model TINY ; memory of model
;------------------------------------------------------------ ;----------------------- CODE SEGMENT -----------------------
.code
org 07c00h ; for BootSector
main:
jmp short start ; go to main
nop
;--------------------- Print a char on the screen ------------
PrintChar PROC
mov ah, 0Eh ;Tell BIOS that we need to print one charater on screen.
mov bh, 0h ;Page no.
mov bl, 07h ;Text attribute 0x07 is lightgrey font on black background int 10h ;Call video interrupt
ret
PrintChar ENDP
;------------------- Print a String on the screen -------------
PrintStr PROC
next_character: ;Lable to fetch next character from string
mov al, [si] ;Get a byte from string and store in AL register
inc si ;Increment SI pointer
or al, al ;Check if value in AL is zero (end of string)
jz exit_function ;If end then return
call PrintChar ;Else print the character which is in AL register
jmp next_character ;Fetch next character from string
exit_function: ;End label
ret
PrintStr ENDP start:
cli ; Clear interrupt flags
mov ax,cs ; Setup segment registers
mov ds,ax ; Make DS correct
mov es,ax ; Make ES correct
mov ss,ax ; Make SS correct
mov bp,7c00h
mov sp,7c00h ; Setup a stack
sti helloString BYTE 'Hello World!', 0
mov si, offset helloString
call PrintStr ; Print the 'Hello World!' string
ret BYTE 510 - ($ - main) DUP(0) ; Fill the reminder of the first sector with zeros
BYTE 55h, 0AAh ; Fill the last two bytes with 55h, 0AAh int the first sector
END main ; End of program

2. 假设第一步中的代码保存为BootLoader.asm,在BootLoader.asm的目录下按住Shift,点击鼠标右键,选择在此处打开命令行(Windows 7系统,其他系统请通过CD指令转到BootLoader.asm文件的目录)。键入下面命令:
ml /AT /omf /Fl /Fm /c BootLoader.asm
C:\Irvine\link6.exe /T /NOD BootLoader.obj
如果提示找不到ml,请添加其路径到环境变量(我的路径为C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\ml.exe)。执行完后,我们将得到BootLoader.com文件。

3. 使用VMware创建一个虚拟机,并新建一块虚拟磁盘(大小1G,预先分配磁盘空间,存储为单文件格式)。将新建的虚拟磁盘格式化为NTFS格式(使用PE或者其他工具)。右击VMWare界面左边的我们新建的虚拟机,进入设置->选中我们新建的磁盘->工具->映射(或者也可以通过菜单的文件->映射虚拟磁盘->映射),出现下面的对话框。去掉read-only的选项,然后点击OK。

4. 打开NtExplorer软件,先进入Tools->Options,将安全模式改为Virtual Write。然后点击菜单File->Drive,选择Z盘。按F3键,进入16进制编辑模式。可以看到扇区0已经有MBR代码了。

将光标位于00位置处,然后选择菜单Edit->Paste from file,选择我们之前生成的BootLoader.com文件。然后选择Tools->Options,点击Write->OK。

5. 再次选择我们新建的虚拟机,进入设置,取消磁盘的映射。然后点击启动虚拟机,你就可以看到Hello World了!

相关资料:
1. How to develop your own Boot Loader
2. Writing Hello World Bootloader
3. Boot sector
[reprint]如何编写引导程序 Hello World的更多相关文章
- 【转载】FAT12格式的引导程序
FAT12格式的引导程序 在上一篇文章中详细介绍了FAT12格式的引导扇区数据结构,详情请浏览: 地址是:http://blog.sina.com.cn/s/blog_3edcf6b80100cr08 ...
- C++编写操作系统(1):基于 EFI 的 Bootloader
很久以前就对操作系统很好奇,用了这么多年Windows,对他的运作机理也不是很清楚,所以一直想自己动手写一个,研究一下操作系统究竟是怎么实现的.后来在网上也找到过一些教程(比如:<自己动手写操作 ...
- 操作系统内核Hack:(三)引导程序制作
操作系统内核Hack:(三)引导程序制作 关于本文涉及到的完整源码请参考MiniOS的v1_bootloader分支. 1.制作方法 现在我们已经了解了关于BootLoader的一切知识,让我们开始动 ...
- Linux shell编写脚本部署pxe网络装机
Linux shell编写脚本部署pxe网络装机 人工安装配置,Linux PXE无人值守网络装机 https://www.cnblogs.com/yuzly/p/10582254.html 脚本实 ...
- 用Shell编写的俄罗斯方块代码
用Shell编写的俄罗斯方块代码 不得不承认任何一门语言玩6了,啥都能搞出来啊,竟然用Shell编写出来了一个俄罗斯方块游戏的代码,很有意思,这个代码不是我写出来的,不过大家可以下载一下在window ...
- 【转载】FAT12格式的引导程序(2)
1.用WinImage来写入到引导区的详细步骤: 启动WinImage后,打开“文件”菜单,单击菜单中的“打开”命令. 选择之前保存的磁盘镜像文件“boot.img”或者“boot.ima”. 打开 ...
- C#编写ActiveX控件
用C#编写ActiveX控件 http://www.cnblogs.com/homer/archive/2005/01/04/86473.html http://www.cnblogs.com/hom ...
- 用C#编写ActiveX控件,开发浏览器控件,注册ActiveX 控件
用C#编写ActiveX控件,开发浏览器控件,注册ActiveX 控件用C#编写ActiveX控件 开发浏览器控件这是本控件开发完成后的一个简单应用.我们可以利用它以本地文件夹为单位来批量更新服务器的 ...
- 用C#编写ActiveX控件
http://www.cnblogs.com/homer/archive/2005/01/04/86473.html http://www.cnblogs.com/homer/archive/2005 ...
随机推荐
- Delphi指针的用法
DELPHI指针的使用 大家都认为,C语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上.因此,说指针是C语言的灵魂,一点都不为过.同时,这种说法也让很多人产生误解,似乎只有C语言的指针才 ...
- The Producer-Consumer Relationship
//Listing 3-1. The Producer-Consumer Relationship Version 1 public class PC { public static void mai ...
- pro7
1.本次课学习到的知识点: 函数的作用 确定函数的功能 定义函数 调用函数 2.实验过程中遇到的问题及解决方法: 定义函数时 变量的定义会出现混乱 通过看例题 多练习 逐渐熟悉 需从数学角度解决问题时 ...
- ios 消息传递机制
引用文章 一.KVO 1.当对象中的某个属性值发生了改变,可以对这些值的观察者做出通知. 2.接受者(会接收到值发生改变的消息) 必须知道发送者(值将发生改变的那个对象). 3.接收者同样还需要知道发 ...
- python 之 range()
range 是一个类,这个类用来实例化生成一个有序的整数序列. range类中定义了__iter__()特殊方法,说明range 类的实例对象都支持迭代. __len__()方法说明 range对象可 ...
- 设计模式:组合模式(Composite)
定 义:将对象组合树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象使用具有一致性. 结构图: Component类: abstract class Component ...
- JSON格式解析和libjson使用简介(关于cjson的使用示例)
JSON格式解析和libjson使用简介 在阅读本文之前,请先阅读下<Rss Reader实例开发之系统设计>一文. Rss Reader实例开发中,进行网络数据交换时主要使用到了两种数据 ...
- 用facebook账号登陆到你的Magento网店
Inchoo提供magento和facebook连接的扩展,可以到http://inchoo.net/ecommerce/magento/facebook-connect-magento-extens ...
- [LeetCode]题解(python):102 Binary Tree Level Order Traversal
题目来源 https://leetcode.com/problems/binary-tree-level-order-traversal/ Given a binary tree, return th ...
- Unofficial Windows Binaries for Python Extension Packages
http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy