第二天内容主要是关于一些寄存器的介绍以及使用。
以下程序是对第一天程序的完善:
; hello-os
; TAB=4
ORG 0x7c00 ; 指明程序的装载地址
; 以下这段是标准FAT12格式软盘专用的代码
JMP entry
DB 0x90
--略--
; 程序核心
entry:
MOV AX,0 ; 初始化寄存器
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
MOV ES,AX
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1 ; 给SI加1
CMP AL,0
JE fin
MOV AH,0x0e ; 显示一个文字
MOV BX,15 ; 指定字符颜色
INT 0x10 ; 调用显卡BIOS
JMP putloop
fin:
HLT ; 让CPU停止,等待指令
JMP fin ; 无限循环
msg:
DB 0x0a, 0x0a ; 换行2次
DB "hello, world"
DB 0x0a ; 换行
DB 0
首先是ORG指令,该指令告诉nask汇编语言编译器,把这些机器语言指令装载带内存中的哪个位置。即程序要从指定的这个地址开始。
JMP指令相当于C语言中的goto。
MOV指令即赋值。它有一个规则,就是源数据和目的数据必须位数相同。就是能向AL里代入的只有BYTE,即 MOV AL, [SI]
ADD是加法指令,ADD SI, 1,即SI = SI + 1
CMP是比较指令,CMP AL, 0则是将AL中的值和0进行比较
JE是条件跳转指令之一,如果比较结果相等则跳转到指定的地址,否则则不跳转,继续执行下一条指令
INT是软件中断指令,INT 0x10则是调用BIOS中与显卡有关的函数。而其中有关的寄存器则是:
AH = 0x0e
AL = character code
BH = 0
BL = color code
AX – 累加寄存器
CX – 计数寄存器
DX – 数据寄存器
BX – 基址寄存器
SP – 栈指针寄存器
BP – 基址指针寄存器
SI – 源变址寄存器
DI – 目的变址寄存器
这些寄存器都是16位寄存器,即每个寄存器可以存储2字节数据。
另外,CPU中还有8个8位寄存器
AL – 累加寄存器低位
CL – 计数寄存器低位
DL – 数据寄存器低位
BL – 基址寄存器低位
AH – 累加寄存器高位
CH – 计数寄存器高位
DH – 数据寄存器高位
BH – 基址寄存器高位
AL和AH使用的空间实际与AX一样,只是AX的0到7位低8位称为AL,而8位到15位的高8位称为AH。
对于BP, SP, SI, DI,如果要取其高位或低位数据,就必须使用MOV AX, SI,将SI的值赋到AX中,然后再用AL、AH来取值。
对于32位系统来说,有对应的扩展寄存器,即EAX、ECX、EDX、EBX、EBP、ESP、ESI、EDI。
还有一些段寄存器:
ES – 附加段寄存器
CS – 代码段寄存器
SS – 栈段寄存器
DS – 数据段寄存器
FS
GS
这些段寄存器都是16位的。
综上可以知道CPU存储能力很差,所以想让CPU处理大量信息,就必须准备一套用于存储的电路,即内存。
认识完这些后可以知道,该程序作用是将msg内容显示出来。首先初始化一些寄存器,将msg标号所代表的地址赋给SI,之后[SI]则是取地址中的内容,即字符,将其赋给AL,调用INT 0x10时,AL保存的是字符编码。当AL不等于0时,即不等于空字符,则继续显示直到等于0,则跳转到fin,在里面挂起CPU。