自制操作系统02

第一天我们用DB生成了一个软盘映像文件,并大言不惭已经学会了汇编。但要搞清楚DB后面的字节值,还是要多学点汇编命令的。
我列一下寄存器名字与功能:
AX--accumulator,累加寄存器
CX--counter,计数寄存器
DX--data,数据寄存器
BX--base,基址寄存器
SP--stack pointer,栈指针寄存器
BP--base pointer,基址指针寄存器
SI--source index,源变址寄存器
DI--destination index,目的变址寄存器


上面A,B,C,D开头的寄存器都有了哈,后面的X表示是extend的,这是相对于8位的,extend就是16位了。哎,我这200块的64位cpu啊。再来两组分别对应高低位上面的寄存器,AH、BH、CH、DH,AL、BL、CL、DL。
上面的寄存器前面加个E,就是extend了,就成了32位的了。
再来一组段寄存器
ES--extra segment 附加段寄存器
CS--code segment 代码段寄存器
SS--stack segment 栈段寄存器
DS--data segment 数据段寄存器
FS--无名
GS--无名

nasm已经不能编译这句命令了
RESB    0x1fe-$            ;
会报错:helloos.nas:58: error: attempt to reserve non-constant quantity of BSS space
$表示是当前命令的地址,我也不知道当前地址,就按昨天计算的380来算吧。改成:
RESB 380
哈哈,居然可以编译成功,正常显示。那么我改成RESB 400呢?居然也可以,那么是不是后面的那句非空的根本没用?先不管了。
我把编译通过的源码,粘一下(原作者第一天的源码):

; hello-os
; TAB=4

; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述

		DB		0xeb, 0x4e, 0x90
		DB		"HELLOIPL"		; ブートセクタの名前を自由に書いてよい(8バイト)
		DW		512				; 1セクタの大きさ(512にしなければいけない)
		DB		1				; クラスタの大きさ(1セクタにしなければいけない)
		DW		1				; FATがどこから始まるか(普通は1セクタ目からにする)
		DB		2				; FATの個数(2にしなければいけない)
		DW		224				; ルートディレクトリ領域の大きさ(普通は224エントリにする)
		DW		2880			; このドライブの大きさ(2880セクタにしなければいけない)
		DB		0xf0			; メディアのタイプ(0xf0にしなければいけない)
		DW		9				; FAT領域の長さ(9セクタにしなければいけない)
		DW		18				; 1トラックにいくつのセクタがあるか(18にしなければいけない)
		DW		2				; ヘッドの数(2にしなければいけない)
		DD		0				; パーティションを使ってないのでここは必ず0
		DD		2880			; このドライブ大きさをもう一度書く
		DB		0,0,0x29		; よくわからないけどこの値にしておくといいらしい
		DD		0xffffffff		; たぶんボリュームシリアル番号
		DB		"HELLO-OS   "	; ディスクの名前(11バイト)
		DB		"FAT12   "		; フォーマットの名前(8バイト)
		RESB	18				; とりあえず18バイトあけておく

; プログラム本体

		DB		0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
		DB		0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
		DB		0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
		DB		0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
		DB		0xee, 0xf4, 0xeb, 0xfd

; メッセージ部分

		DB		0x0a, 0x0a		; 改行を2つ
		DB		"hello, world"
		DB		0x0a			; 改行
		DB		0

		;RESB	0x1fe-$			; 0x001feまでを0x00で埋める命令
		RESB	400

		DB		0x55, 0xaa

; 以下はブートセクタ以外の部分の記述

		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	4600
		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	1469432


第二天的源码,同样要改一下$那行就能编译通过。看一下今天的源码:
; hello-os
; TAB=4

		ORG		0x7c00			; 把程序以下程序加载到内存的0x7c00,即引导区

; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述

		JMP		entry
		DB		0x90
		DB		"HELLOIPL"		; ブートセクタの名前を自由に書いてよい(8バイト)
		DW		512				; 1セクタの大きさ(512にしなければいけない)
		DB		1				; クラスタの大きさ(1セクタにしなければいけない)
		DW		1				; FATがどこから始まるか(普通は1セクタ目からにする)
		DB		2				; FATの個数(2にしなければいけない)
		DW		224				; ルートディレクトリ領域の大きさ(普通は224エントリにする)
		DW		2880			; このドライブの大きさ(2880セクタにしなければいけない)
		DB		0xf0			; メディアのタイプ(0xf0にしなければいけない)
		DW		9				; FAT領域の長さ(9セクタにしなければいけない)
		DW		18				; 1トラックにいくつのセクタがあるか(18にしなければいけない)
		DW		2				; ヘッドの数(2にしなければいけない)
		DD		0				; パーティションを使ってないのでここは必ず0
		DD		2880			; このドライブ大きさをもう一度書く
		DB		0,0,0x29		; よくわからないけどこの値にしておくといいらしい
		DD		0xffffffff		; たぶんボリュームシリアル番号
		DB		"HELLO-OS   "	; ディスクの名前(11バイト)
		DB		"FAT12   "		; フォーマットの名前(8バイト)
		RESB	18				; とりあえず18バイトあけておく

; プログラム本体

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

		;RESB	0x7dfe-$		; 0x7dfeまでを0x00で埋める命令
		RESB	380

		DB		0x55, 0xaa

; 以下はブートセクタ以外の部分の記述

		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	4600
		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	1469432


先解析下0x7c00这个数,它就是内存的引导区地址。ORG 0x7c00就是把本程序加载到0x7c00这个内存地址上.这个博客(https://blog.csdn.net/z929118967/article/details/49995669)说了下0x7c00的来历,大概意思是当时内存是32k,就选了这个地址。
JMP就是跳转命令,与C语言的goto一样。
entry程序段是初始化,前面几句都是初始化值,没什么好说的,后面有句MOV SI,msg 而msg是一程序段标签名,它的意思是把msg这段代码的地址放进SI寄存器。
看来这段汇编程序会从上到下顺序执行,否则hello,world怎么显示出来的?
putloop也是顺序执行的,第一句
MOV        AL,[SI]
而SI存的是msg地址,仔细看下msg的代码,哈,就是我们第一天的DB大法(RESB也一样),没什么特别的。
ADD SI,1 ; 就是地址加1字节吧
CMP AL,0
JE fin
这两句意思是if(Al==0){goto fin;}
MOV AH,0x0e ;这个MOV据说是显示一个文字
MOV BX,15 ;指定字符颜色

INT 0x10;调用显卡BIOS,就是调用显示命令了

这里我增加一个老的中文资料1989年的《IBMPCPC XTPC AT长城DOSBIOS功能调用手册》,说明INT 0x10的用法:

再jump到putloop,就是要死循环了,直到SI加到msg的末尾,这时AL等于0(我也不知为什么=0),跳到fin段程序。
作者在第二天介绍了make的使用,我的环境与作者的也不一样,make的用法我以前也介绍过,这里就不多说了。


文/中中 浏览次数:0次   2020-04-05 21:59:24

相关阅读


评论: