【分析】
部分代码
mov dh, 0 ; "Booting "
call DispStr ; 显示字符串
跳转到这个函数
;----------------------------------------------------------------------------
; 函数名: DispStr
;----------------------------------------------------------------------------
; 作用:
; 显示一个字符串, 函数开始时 dh 中应该是字符串序号(0-based)
DispStr:
mov ax, MessageLength
mul dh
add ax, BootMessage
mov bp, ax ; ┓
mov ax, ds ; ┣ ES:BP = 串地址
mov es, ax ; ┛
mov cx, MessageLength ; CX = 串长度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 0007h ; 页号为0(BH = 0) 黑底白字(BL = 07h)
mov dl, 0
int 10h
ret
说明,此函数的实现仍然是Int 10H中断
使用了AH=13H的功能
功能号:13H
功能:在Teletype模式下显示字符串
入口参数:AH=13H
BH=页码
BL=属性(若AL=00H或01H)
CX=显示字符串长度
(DH、DL)=坐标(行、列)
ES:BP=显示字符串的地址 AL= 显示输出方式
0—字符串中只含显示字符,其显示属性在BL中。显示后,光标位置不变
1—字符串中只含显示字符,其显示属性在BL中。显示后,光标位置改变
2—字符串中含显示字符和显示属性。显示后,光标位置不变
3—字符串中含显示字符和显示属性。显示后,光标位置改变
具体参看http://www.programfan.com/blog/article.asp?id=16290内容
好,一句句分析
代码中跳入函数体前,dh=0h,
随后ax=MessageLength(ps,此MessageLength在后续代码中定义为9)
后面一句mul dh
这里先看下mul指令
mul指令是乘法指令,无符号乘。使用mul做乘法的时候:
1) 两个相乘的数:两个相乘的数,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另外一个存放在8为寄存器或字节内存单元中;如果是16位,一个默认在AX中,另外一个放在16为寄存器或内存寄存器字单元中。
2) 结果:如果是8位乘法,结果默认放在AX中;如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。
格式:
mul reg
mul 内存单元
内存单元可以用不同的寻址方式给出,比如:
mul byte ptr ds:[0]
含义:(ax) =(al)*((ds)*16+0);
mul word ptr [bx+si+8]
含义:(ax) =(ax)*((ds)*16+(si)+8)结果的低16位;(dx) =(ax)*((ds)*16+(si)+8)的结果的高16位。
例如:
计算100*10
分析:100和10小于255,可以做8为乘法。
mov al, 100
mov bl, 10
mov bl
结果:(ax) =03E8H(即是:1000).
计算100*10000
分析:100小于255,10000大于255,所以必须做16位乘法。
mov ax, 100
mov bx, 10000
mul bx
结果:(ax) =4240H, (dx) =000FH(总的结果:F4240H =1000000).
这个部分可以看出乘法结果放在AX寄存器中
回到代码中,mul dh,结果Ax=0
随后add ax, BootMessage,把BootMessage地址给了Ax
mov bp, ax
mov ax, ds
mov es, ax
这三句实现“ES:BP=显示字符串的地址(参看int 10H,AH=13h功能描述)”,其中es用ds来复制,说明串数据来源于DS数据段寄存器
后面代码根据AH=13h功能描述,也就明了了
mov cx, MessageLength ; CX = 串长度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 0007h ; 页号为0(BH = 0) 黑底白字(BL = 07h)
mov dl, 0
最后,看下各个寄存器到底放了什么数据
AX 01301h
BX 0007h
CX 9=1001h
DX=DH+DL=0h,说明输出坐标是(0,0)
ES=DS
BP=BootMessage地址
OK,关于DispStr函数的分析就此结束~~
回过头看下loader.s的代码,发现这个又是另一种输出的方式,直接在显存地址上输出
mov ax, 0B800h;0B800h是PC机显存的开始地址,http://hi.baidu.com/numax/blog/item/9c51e464f8d736f8f6365439.html
mov gs, ax
mov ah, 0Fh ; 0000: 黑底 1111: 白字
mov al, 'L'
mov [gs:((80 * 0 + 39) * 2)], ax ; 屏幕第 0 行, 第 39 列。
输出的"L"字符
有些硬件的相关内容很重要~