升级版的彩色Hello,OS
2013-4-21 21:00
==================
升级版的彩色Hello,OS
——我对boot.asm的理解
你的Hello,OS程序一定是这样的:
这个Hello,OS很单调,而且屏幕上充斥着“垃圾信息”。
我的Hello,OS是这样的:
是不是比原来的程序高端很多?其实只要经过小小的更改,就可以写出这个彩色的升级版Hello,OS。接下来我们一起探究一下如何编写这个程序。
第一步:理解原版的Hello,OS
下面将原版boot.asm代码分成几段来说明
1. org 7c00h
首先说明启动电脑以后所要做的事情
- 电源复位
- BIOS 程序被执行
- Boot 内容被执行
有关Boot结构的规则
- 必须是一个二进制文件(COM format)
- 必须是512个字节
- 最后两个子节必须是0xAA55h
- 被读入内存的地址是7C00h
org指令的作用是根据其指定的偏移量,计算段内数据的各种偏移。即原地址加上org指定的偏移形成数据的实际偏移地址。如果不写org指令,则相当于org 0,即段内偏移地址为0。那么我们为什么把偏移设为7c00h呢?因为我们写的程序是仿照Linux操作系统的内核引导代码,当PC启动时,BIOS会把启动盘的第一扇区加载到内存0x7c00地址处,然后从此地址开始执行,程序使用数据时(例如“Hello,OS!”字符串)所用地址与此相关,org指令使得不用反复写偏移地址就能方便的使用数据。
2. mov ax,cs
mov ds,ax
mov es,ax
“mov 寄存器a,寄存器b”这个指令把寄存器b的值赋给寄存器a。
CS是代码段寄存器,代码段1中org 7c00h指令使得CS = 0x7c00。
在代码段2中,先将CS的值赋给AX,然后将AX的值赋给了DS,DS是数据段寄存器。
你可能会有疑问:为什么不直接写mov ds,cs呢?因为8086cpu不支持将数据直接送入段寄存器的操作,因此先送入AX,然后送入DS。
ES是附加段寄存器,这里赋给它与CS相同的值,当要处理两个字符串时,例如比较两个字符串,设置两个段寄存器会使操作更方便,当所处理的字符串在同一段内时,可以让DS和ES相等。我们这里只需要打印一个字符串,只涉及同一段数据,因此ES与DS相等。
3. call DispStr
jmp $
call DispStr相当于push IP然后jmp DispStr,即保存指令指针然后跳转至DispStr标记处,也就是相当于函数调用了,而jmp $是跳转到哪里呢?首先说明一下jmp的跳转方式,即跳转到 (IP) = (IP)+标号地址-JMP指令后第一个字节的地址。这里$表示当前指令的地址,于是跳转的目标地址就等于(IP)+(IP)-(IP)=(IP),还是当前指令,这就造成了一个无限循环,使得这条指令无限的执行下去。
4. DispStr:
mov ax,BootMessage
mov bp,ax
DispStr:是一个标记,表示它下面第一条指令与段寄存器的相对地址。
BootMessage就是代码最下面的BootMessage数据段相对于数据段寄存器DS的偏移地址。BP称为基址指针寄存器,在作数组和字符串运算时,用于存放内存的偏移地址。这里存放了“Hello,OS!”这个字符串相对于ES的偏移地址,其实际地址为ES:BP。
5. mov cx,16
mov ax,1301h
mov bx,000ch
mov dl,0
int 10h
ret
4、5这两个代码段的功能将字符串输出到屏幕,INT 10H是由 BIOS 对屏幕及显示器所提供的服务程序。
使用 INT 10H 中断服务程序时,先指定 AH 寄存器,该寄存器表示欲调用的功能,而其他寄存器是该功能的一些“属性”,当一切设定好之后再调用 INT 10H 即可。
CX:输出到屏幕的字符个数。
AH:AX的高八位,AH中的值表示10h号中断的子程序号,我们这里AH = 0x13,是10h号中断的13h号子程序,注意下面各个寄存器所代表的含义是基于AH = 0x13的,若调用其他号子程序,则意义不一定相同。
AL:AX的低八位,表示光标的初始位置以及字符串打印形式,我们这里AL = 1,表示光标跟随移动并且字符串为“charcharchar……”这样的形式(即普通的字符串)。
DH:DX的高八位,表示当前打印的字符所在行号,我们这里DH = 0,即第0行。
DL:DX的低八位,表示当前打印的字符所在列号,我们这里DL = 0,表示字符串的第一个字符从屏幕上0列开始打印。
BH:页号,我们这里BH = 0;
BL:当前打印的字符的颜色,这个寄存器可以帮助我们打印出前面展示的彩色字符串,对于原版Hello,OS程序,BL = 0x0c,是淡红色,稍后我们会给出它能表示的所有颜色。
ret: 函数执行完毕,返回调用处。
6. BootMessage: db "Hello,OS!"
times 510-($-$$) db 0
db表示存储字节型数据,一个字符正好占一个字节的空间。这里的字符串占据了多个字符的空间。
times 510-($-$$) db 0:“times 循环次数 数据”指令表示用某种数据填充数据段,这里$表示当前指令相对于CS的地址,$$表示一个节的开始处被汇编后的地址,我们这里程序只有一个节,因此$$就相当于7c00h,510-($-$$)就等于510减去我们的程序长度的到的值。后边db 0表示用字节型数据0填充我们程序后面的位置,即 “Hello,OS!” 字符串后面全部为ASCII为0的字符 (NULL) 。
7. dw 0xaa55
dw表示字型数据,0xaa55占据一个字的空间,表示代码段的结尾。
第6段代码的510-($-$$)中的510与此相关,8086cpu一个字占据两个字节的空间,我们写的启动扇区的程序运行时共占据512个字节,510就是有512-2这样得来的。
以上终于介绍完了原版的boot.asm,接下来介绍如何使其“升级”为彩色版 :P
第二步:彩色的Hello,OS!
我们需要几个更“高级”一点的汇编知识:使用循环语句、使用堆栈和寄存器的加法操作。
1. 使用循环
基本语法的示例:
mov cx,10 ;;循环执行的次数在循环标记前放入CX中,这里循环体将执行10次
label: ;;循环每执行一次,CX中的值都会减一,直到CX=0时跳出循环
…… …… ;;循环体
loop label
2. 使用堆栈
基本语法的示例:
push cx ;;将CX的值压入栈中
………… ;;注意这里某些指令可能会更改CX的中的值
…………
pop cx ;;将先前保存的CX出栈,CX恢复原来的值
3. 寄存器加法
基本语法的示例:
add ax,1 ;;ax=ax+1
我们程序的基本思路是循环打印15次"Hello,OS! Created by HaoXin:P"这句话,每句话的颜色不一样,每打印一句话变更一次颜色,我们已经知道BL表示颜色,其颜色表如下:
|
二进制数 |
颜色 |
例子 |
二进制数 |
颜色 |
例子 |
|
0000 |
黑色 |
black |
1000 |
灰色 |
gray |
|
0001 |
蓝色 |
blue |
1001 |
淡蓝色 |
light blue |
|
0010 |
绿色 |
green |
1010 |
淡绿色 |
light green |
|
0011 |
青色 |
cyan |
1000 |
淡青色 |
light cyan |
|
0100 |
红色 |
red |
1100 |
淡红色 |
light red |
|
0101 |
紫红色 |
magenta |
1101 |
淡紫红色 |
light magenta |
|
0110 |
棕色 |
brown |
1110 |
黄色 |
yellow |
|
0111 |
银色 |
light gray |
1111 |
白色 |
white |
有16种颜色,但0000这个颜色与屏幕背景色同为黑色,所以我们只打印15种颜色。
具备以上知识点就可以了,接下来给出彩色版boot.asm的源代码以及注释:
org 7c00h
mov ax,cs ;cs=07c00h,ax=cs
mov ds,ax ;ds=07c00h
mov es,ax ;es=07c00h
call DispStr ;push IP, jmp DispStr
jmp $ ;infinite loop
DispStr:
mov dh,0 ;行号,初始为零,从屏幕第0行开始打印
mov bh,00h ;页号为0参见前面的讲解
mov dl,0 ;列号为0参见前面的讲解
mov bl,1 ;颜色,第一种设为0001,参见前面的颜色表
mov ax,BootMessage ;;
mov bp,ax ;;ES:BP = 字符串地址
mov cx,15 ;循环次数
print: ;循环标记
push cx ;由于打印字符串需要更改CX,我们先保存CX循环计数的值到堆栈
mov cx,80 ;打印长度为80,覆盖所有“垃圾信息”
mov ax,1301h ;子程序号AH = 0x13,光标位置AL = 0x01详见前面的讲解
int 10h ;int 10h中断服务程序
add dh,1 ;行号加1,目的是使下一句打印到下一行
add bl,1 ;颜色号加1,换下一个颜色
pop cx ;出栈,还原CX为循环次数的值
loop print ;循环
ret ;函数返回
BootMessage: db "Hello,OS! Created by HaoXin:P" ;;字节型数据
times 510-($-$$) db '_' ;;填充剩余空间,我们用下划线来代替空字符,^_^
dw 0xaa55 ;;程序结束标志
接下来编写你自己的彩色Hello,OS吧!

浙公网安备 33010602011771号