x86 汇编语言:从真实模式到保护模式(第 5 章 - 编写主引导扇区代码)
在前面的预备知识里,我们已经知道,处理器加电或者复位之后,如果硬盘是首选的启动设备,那么,ROM-BIOS 将试图读取硬盘的 0 面 0 道 1 扇区。传统上,这就是主引导扇区(Main Boot Sector,MBR)。
读取的主引导扇区数据有 512 字节,ROM-BIOS 程序将它加载到逻辑地址 0x0000:0x7c00处,也就是物理地址 0x07c00 处,然后判断它是否有效。一个有效的主引导扇区,其最后两字节应当是 0x55 和 0xAA。ROM-BIOS 程序首先检测这两个标志,如果主引导扇区有效,则以一个段间转移指令 jmp 0x0000:0x7c00 跳到那里继续执行。
一般来说,主引导扇区是由操作系统负责的。正常情况下,一段精心编写的主引导扇区代码将检测用来启动计算机的操作系统,并计算出它所在的硬盘位置。然后,它把操作系统的自举代码加载到内存,也用 jmp 指令跳转到那里继续执行,直到操作系统完全启动。在本章中,我们将试图写一段程序,把它编译之后写入硬盘的主引导扇区,然后让处理器执行(这段代码的作用是完成某个数的各个数位的拆分,并显示在屏幕上)。
显存
如图 5-3 所示,我们知道,8086 可以访问 1MB 内存。其中,0x00000~9FFFF 属于常规内存,由内存条提供;0xF0000~0xFFFFF 由主板上的一个芯片提供,即 ROM-BIOS。中间还有一个 320KB 的空洞,即 0xA0000~0xEFFFF。传统上,这段地址空间由特定的外围设备来提供,其中就包括显卡(0xB8000~0xBFFFF)。如果显卡出了毛病,计算机一定不会通过加电自检过程,这就是传说中的严重错误,计算机是无法启动的,更不要说加载并执行主引导扇区的内容了。
传统上,这种专门用于显示字符的工作方式称为文本模式(80×25,屏幕上可以显示 25 行,每行 80 个字符 )。为了给出要显示的字符,处理器需要访问显存,把字符的 ASCII 码写进去。屏幕上的每个字符对应着显存中的两个连续字节,前一个是字符的 ASCII 代码,后面是字符的显示属性,包括字符颜色(前景色)和底色(背景色)(现在最流行的,是用 24 个比特,即 3 个字节,来对应一个像素。因为 2 24 =16777216,所以在这种模式下,同屏可以显示 16777216 种颜色,这称为真彩色。)。
编程示例(将载入主引导扇区)
本代码的作用是完成某个数的各个数位的拆分,并显示在屏幕上。
div
- 第一种类型是用 16 位的二进制数除以 8 位的二进制数。在这种情况下,被除数必须在寄存器AX 中,必须事先传送到 AX 寄存器里。除数可以由 8 位的通用寄存器或者内存单元提供。指令执行后,商在寄存器 AL 中,余数在寄存器 AH 中。
- 第二种类型是用32位的二进制数除以16位的二进制数。在这种情况下,因为 16 位的处理器无法直接提供 32 位的被除数,故要求被除数的高 16 位在DX 中,低 16 位在 AX 中。同时,除数可以由 16 位的通用寄存器或者内存单元提供,指令执行后,商在 AX 中,余数在DX 中。
在编译阶段,每条指令都被计算并赋予了一个汇编地址,就像它们已经被加载到内存中的某个段里一样。实际上,当编译好的程序加载到物理内存后,它在段内的偏移地址和它在编译阶段的汇编地址是相等的。
jmp
jmp 0x5000:0xf0c0 ;同时修改CS和IP
jmp near infi ;(IP) = (IP) + 16位位移
;16位位移=标号处地址-jmp指令的下一条指令的地址(当前的CS:IP)
代码实现
;文件名:c05_01_mbr.asm
;文件说明:硬盘主引导扇区代码
;参考书:《x86汇编语言:从实模式到保护模式》李忠 著
;代码功能:拆分代码中的标号number对应偏移地址的十进制各个数位,
; 在屏幕上显示Label offset:number对应偏移地址的十进制数。
mov ax,0xb800 ;指向文本模式的显示缓冲区
mov es,ax
;往显存中写入"Label offset:"字符串
mov byte [es:0x0000],'L'
mov byte [es:0x0001],0x07 ;黑底白字,下同
mov byte [es:0x0002],'a'
mov byte [es:0x0003],0x07
mov byte [es:0x0004],'b'
mov byte [es:0x0005],0x07
mov byte [es:0x0006],'e'
mov byte [es:0x0007],0x07
mov byte [es:0x0008],'l'
mov byte [es:0x0009],0x07
mov byte [es:0x000a],' '
mov byte [es:0x000b],0x07
mov byte [es:0x000c],'o'
mov byte [es:0x000d],0x07
mov byte [es:0x000e],'f'
mov byte [es:0x000f],0x07
mov byte [es:0x0010],'f'
mov byte [es:0x0011],0x07
mov byte [es:0x0012],'s'
mov byte [es:0x0013],0x07
mov byte [es:0x0014],'e'
mov byte [es:0x0015],0x07
mov byte [es:0x0016],'t'
mov byte [es:0x0017],0x07
mov byte [es:0x0018],':'
mov byte [es:0x0019],0x07
;拆分number对应偏移地址的十进制各个数位
mov ax,number ;准备被除数
mov bx,10 ;准备除数
mov cx,cs ;设置数据段基地址
mov ds,cx
;求得个位(用32位/16位的div,下同)
xor dx,dx ;高位在dx,清零,比mov dx,0的机器码短,且两个寄存器操作速度快
div bx
mov [0x7c00+number+0x00],dl ;除以10余数小于2^4,取dl即可,注意偏移地址
;求得十位
xor dx,dx
div bx
mov [0x7c00+number+0x01],dl
;求得百位
xor dx,dx
div bx
mov [0x7c00+number+0x02],dl
;求得千位
xor dx,dx
div bx
mov [0x7c00+number+0x03],dl
;求得万位
xor dx,dx
div bx
mov [0x7c00+number+0x04],dl
;把各个数位的数转成ASCII字符,送入显存
mov al,[0x7c00+number+0x04]
add al,0x30 ;'0'对应的ASCII是48,即0x30,数位加上0x30即可转化为该数字字符对应的ASCII
mov [es:0x001a],al
mov byte [es:0x001b],0x04 ;黑底红字,下同
mov al,[0x7c00+number+0x03]
add al,0x30
mov [es:0x001c],al
mov byte [es:0x001d],0x04
mov al,[0x7c00+number+0x02]
add al,0x30
mov [es:0x001e],al
mov byte [es:0x001f],0x04
mov al,[0x7c00+number+0x01]
add al,0x30
mov [es:0x0020],al
mov byte [es:0x0021],0x04
mov al,[0x7c00+number+0x00]
add al,0x30
mov [es:0x0022],al
mov byte [es:0x0023],0x04
mov byte [es:0x0024],'D' ;添加一个D十进制数标志
mov byte [es:0x0025],0x07
infi:
jmp near infi ;使得程序在此死循环,避免程序往下走到非代码区
number:
db 0,0,0,0,0 ;开5个字节,存放number对应偏移地址的5个数位
times 204 db 0 ;填充使得正好凑够512个字节
db 0x55,0xaa ;主引导扇区有效结束标志(低地址到高地址)
编译后的十六进制机器码
由此可知,number标号对应的十六进制偏移地址是0x012d,对应十进制301。如果没问题的话,之后虚拟机启动之后显示的十进制数将是00301D。
把c05_01_mbr.bin写入主引导扇区
启动虚拟机Virtual Box观察运行结果
Bochs程序调试入门
本书中的程序全都只能运行在没有操作系统的祼机下。这意味着,所有流行的调
试工具都不可用。不过,好消息是,一款叫做 Bochs 的软件可以帮助你。
下载安装与配置
下载地址(下载最新版本)
安装之后如下:
在 Bochs 的工作文件夹,有两个程序,分别是 bochs.exe 和 bochsdbg.exe。我们说过,Bochs 是虚拟机软件,可以作为类似于 VirtualBox 的虚拟机来使用。在这种情况下,你应当使用 bochs.exe。相反,如果你希望用 Bochs 来调试程序,那么,应当使用 bochsdbg.exe,它的意思是“Bochs 调试”(Bochs Debuger)。
在“Bochs Start Menu”窗口中,双击“Edit Options”列表框中的“Disk & Boot”,如下设置。柱面数、磁头数和扇区数可以用fixvhdwr.exe程序打开.vhd文件显示查到。
点击save,保存到 Bochs 的安装文件夹。
调试演示
Bochs错误及解决方案
笔者第一次进入Bochs,按照教程设置完毕无误,可以正常调试,但是第二次就报错了。。反复重装还是报错。。。
解决方法:
- 在Virtual Box虚拟机目录下自己创建的虚拟机LEARN-ASM下查看,如果有文件LEARN-ASM.vhd.lock,删除掉这个文件。
- 以管理员身份运行。。。
特别说明
本文参考《x86汇编语言:从实模式到保护模式》李忠 著
上一篇: 安卓摄像机输出流和剪切
下一篇: 800*480bmp 图像显示