<自己动手写操作系统>2011033001

【分析】

部分代码

    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"字符

有些硬件的相关内容很重要~
原文地址:https://www.cnblogs.com/GoGoagg/p/1999986.html