现在开始本书的Day 2:
先看看作者提供的代码:
; hello-os
; TAB=4ORG 0x7c00 ;告诉nask,在开始执行的时候,把这些机器语言指令装载到内存中为0x7c00的地址JMP entry ; JMP的意思是“跳转”,DB 0x90DB "HELLOIPL"DW 512DB 1DW 1DB 2DW 224DW 2880DB 0xf0DW 9DW 18DW 2DD 0DD 2880DB 0,0,0x29DD 0xffffffffDB "HELLO-OS "DB "FAT12 "RESB 18entry: ; 用于指定JMP指令的跳转目的地。entry意为“入口”MOV AX,0 ; 相当于"AX=0",也就是将AX赋值为0MOV SS,AX ; 相当于"SS=AX=0"MOV SP,0x7c00 ; 给栈指针寄存器赋值0x7c00MOV DS,AX ; 相当于“DS=AX=0”MOV ES,AX ; 相当于“ES=AX=0”MOV SI,msg ; 在这里msg的地址是0x7c74,所以这个指令是要把0x7c74带入到SI寄存器去
putloop:MOV AL,[SI] ;方括号表示内存地址,这个指令的意思是“把SI地址的一个字节的内容读入到AL中”ADD SI,1 ; ADD为加法指令,这个指令相当于SI=SI+1CMP AL,0 ; CMP是比较指令,将AL中的值与0进行比较,而这条指令的下一条指令表示“如果二者相等,需要做什么”JE fin ; JE是一种条件跳转指令,如果上一句的比较结果相等,则跳转到指定的地址,如果比较结果不等,则不跳转MOV AH,0x0eMOV BX,15INT 0x10; INT是软件中断指令,计算机的BIOS程序本质上是为操作系统开发人员准备的函数集合,INT是用来调用这些函数的指令,INT后面的数字不同,调用的函数也不同JMP putloop
fin: ; fin作为标号,有“结束”的意思(finish)HLT ; 这个指令能让CPU处于待机状态JMP fin
msg:DB 0x0a,0x0aDB "hello, world"DB 0x0aDB 0RESB 0x7dfe-$DB 0x55,0xaaDB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00RESB 4600DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00RESB 1469432
ORG指令源自于英文“origin", 意味源头、起点。它告诉nask。程序要从指定的这个地址开始,也就是要把程序装载到内存中的指定地址,而在上述程序中指定的地址是0x7c00
下面介绍一些16位寄存器:
AX: 累加寄存器
CX: 计数寄存器
DX: 数据寄存器
BX: 基址寄存器
SP: 栈指针寄存器
BP: 基址指针寄存器
SI: 原变址寄存器
DI:目的变址寄存器
另一方面,CPU还有8个高位寄存器:
AL:累加寄存器低位
AH:累加寄存器高位
CL:计数寄存器低位
CH:计数寄存器高位
DL:数据寄存器低位
DH:数据寄存器高位
BL:基址寄存器低位
BH:基址寄存器高位
AX寄存器共有16位,其中0位到7位的低8位,而8位到15位的高8位称为AH。
还有几个16位的段寄存器:
ES:附加段寄存器
CS:代码段寄存器
SS:栈段寄存器
DS:数据段寄存器
FS:(没有名称)
GS:(没有名称)
之所以能用“JMP entry”代替“JMP 0x7c50"是因为entry就是0x7c50,在汇编语言中,所有标号都是单纯的数字。每个标号对应的数字,都是由汇编语言编译器根据ORG指令计算出来的。编译器计算出的“标号的地方对应的内存地址”就是标号的值。
BYTE、WORD、DWORD也是汇编语言的保留字
像这样在汇编语言里指定内存地址时,要用下面这种方式来写: 数据大小 [地址]
如果数据大小为BYTE,那么使用的存储单元就只是地址所指定的字节。如果数据大小为WORD,则相邻的一个字节也会成为这个指令的操作对象,如果为DWORD,则与WORD相邻的两个字节(总共四个字节),也会成为操作对象。这里所说的相邻,指的是地址增加方向的相邻。
如果寄存器SI保存的是987,那么"BYTE [SI]“就会被解释成"BYTE [987]”。即指定地址为987的内存。
但是能用来指定内存地址的寄存器只有BX、BP、SI、DI这几个。
想把DX内存里的内容赋值给AL,可以这么写:
MOV BX, DX
MOV AL, BYTE [BX]
MOV指令有一个规则,那就是源数据和目的数据必须位数相同