00. 寄存器

16位寄存器

1
2
3
4
5
6
7
8
AX —— accumulator,累加寄存器 
CX —— counter,计数寄存器
DX —— data,数据寄存器
BX —— base,基址寄存器
SP —— stack pointer,栈指针寄存器
BP —— base pointer,基址指针寄存器
SI —— source index,源变址寄存器
DI —— destination index,目的变址寄存器

8位寄存器

1
2
3
4
5
6
7
AL —— 累加寄存器低位(accumulator low) 
CL —— 计数寄存器低位(counter low)
DL —— 数据寄存器低位(data low)
BL —— 基址寄存器低位(base low)
AH —— 累加寄存器高位(accumulator high)
CH —— 计数寄存器高位(counter high)
DH —— 数据寄存器高位(data high)

32 位寄存器

EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI

段寄存器

1
2
3
4
5
6
ES——附加段寄存器(extra segment) 
CS——代码段寄存器(code segment)
SS——栈段寄存器(stack segment)
DS——数据段寄存器(data segment)
FS——没有名称(segment part 2)
GS——没有名称(segment part 3)

01. 再修改的代码

简而言之,该代码将寄存器初始化后,SI指向消息区域,通过循环不断移动指针,读取其内容,对AX寄存器操作以显示字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
; hello-os
; TAB=4

ORG 0x7c00 ; 指明程序的装载地址

; 以下是标准FAT12格式软盘专用的代码 该段80字节

JMP entry
DB 0x90
DB "HELLOIPL" ; 启动区的名称可以是任意的字符串(8字节) 0x48, 0x45, 0x4c, 0x4c, 0x4f 0x49, 0x50, 0x4c
DW 512 ; 每个扇区(sector)的大小(必须为512字节) 0x00, 0x02,
DB 1 ; 簇(cluster)的大小(必须为1个扇区) 0x01
DW 1 ; FAT的起始位置(一般从第一个扇区开始) 0x01, 0x00
DB 2 ; FAT的个数 0x02,
DW 224 ; 根目录的大小(一般设成224项) 0xe0, 0x00
DW 2880 ; 该磁盘的大小(必须是2880扇区) 0x40, 0x0b
DB 0xf0 ; 磁盘的种类(必须是0xf0) 0xf0
DW 9 ; FAT的长度(必须是9扇区)0x09, 0x00
DW 18 ; 1个磁道(track)有几个扇区(必须是18) 0x12, 0x00
DW 2 ; 磁头数(必须是2) 0x02, 0x00,
DD 0 ; 不使用分区,必须是0 0x00, 0x00, 0x00, 0x00
DD 2880 ; 重写一次磁盘大小 0x40, 0x0b, 0x00, 0x00,
DB 0,0,0x29 ; 意义不明,固定 0x00, 0x00, 0x29
DD 0xffffffff ; (可能是)卷标号码 0xff, 0xff, 0xff, 0xff
DB "HELLO-OS " ; 磁盘的名称(11字节) 0x48, 0x45, 0x4c, 0x4c, 0x4f,0x2d, 0x4f, 0x53, 0x20, 0x20, 0x20
DB "FAT12 " ; 磁盘格式名称(8字节) 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20
RESB 18 ; 先空出18字节

; 程序核心 开始地址:0x7c50

entry:
MOV AX,0 ; 将立即数0移动到AX寄存器。这行代码的作用是将AX寄存器初始化为0。
MOV SS,AX ; 将AX寄存器的内容移动到SS寄存器。这行代码的作用是将栈段寄存器SS初始化为0。
MOV SP,0x7c00 ; 将立即数0x7c00移动到SP寄存器。这行代码的作用是将栈指针寄存器SP设置为0x7c00,这是引导扇区的内存地址。
MOV DS,AX ; 将AX寄存器的内容移动到DS寄存器。这行代码的作用是将数据段寄存器DS初始化为0。
MOV ES,AX ; 将AX寄存器的内容移动到ES寄存器。这行代码的作用是将附加段寄存器ES初始化为0。

MOV SI,msg ; 将标号msg的地址移动到SI寄存器。这行代码的作用是将SI寄存器设置为存储消息字符串的内存地址。

; 通过循环,该段代码会逐个字符地读取字符串并在屏幕上显示,直到遇到字符串的结束符(空字符)为止。
putloop:
MOV AL,[SI] ; 将SI寄存器指向的内存位置的值移动到AL寄存器。这行代码的作用是将字符串中的一个字符加载到AL寄存器。
ADD SI,1 ; 将SI寄存器的值加1。这行代码的作用是将SI寄存器递增,使其指向下一个字符。
CMP AL,0 ; 将AL寄存器的值与0进行比较。这行代码的作用是检查当前字符是否为字符串的结束符(空字符)。
JE fin ; 如果前面的比较结果等于(Jump Equal)0,则跳转到标号fin,即结束循环。
MOV AH,0x0e ; 将立即数0x0E移动到AH寄存器。这行代码的作用是设置显示功能号为0x0E,表示显示一个字符。
MOV BX,15 ; 将立即数15移动到BX寄存器。这行代码的作用是将字符的颜色属性设置为15,这里的15代表白色字符。
INT 0x10 ; 调用显卡BIOS的中断服务例程,以显示AL寄存器中的字符。这行代码的作用是将字符显示在屏幕上。
JMP putloop ; 无条件跳转回标号putloop,即循环的起始点,继续下一次循环。
fin:
HLT ; 让CPU停止,等待指令
JMP fin ; 无限循环

msg:
DB 0x0a, 0x0a ; 换行2次
DB "hello, world"
DB 0x0a ; 换行
DB 0

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

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
  • ORG指令: 告诉nask,在开始执行时把这些机 器语言指令装载到内存中的哪个地址。如果没有它,有几个指令就不能 被正确地翻译和执行。另外,有了这条指令的话,美元符(**$**)的含义也随之变化,它不再是指输出文件的第几个字节,而是代表将要读入的内存地址。
  • JMP指令:相当于 goto
  • entry: 指令:标签声明
  • MOV指令:赋值,MOV AX,0 相当于 AX=0
  • JE指令:相等就跳转
  • INT指令:中断
  • HLT指令:让CPU停止动作的指令,让CPU进入待机状态。

问题:

  • 为什么是 ORG 0x7c00

    内存某些地方存放着 BIOS 程序,要避免从图,产生错误,这些地方不能用,有下面空间使用:

    0x00007c00-0x00007dff :启动区内容的装载地址

    所以从 0x7c00 开始

  • 为什么 [SI] 要加方括号?

    取地址为 SI 的内存值

02. 制作启动区(保留前部)

解耦合,只保留hellos.nas前半部分,用来制作512字节的启动区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
; hello-os
; TAB=4

ORG 0x7c00 ; 指明程序的装载地址

; 以下是标准FAT12格式软盘专用的代码 该段80字节

JMP entry
DB 0x90
DB "HELLOIPL" ; 启动区的名称可以是任意的字符串(8字节) 0x48, 0x45, 0x4c, 0x4c, 0x4f 0x49, 0x50, 0x4c
DW 512 ; 每个扇区(sector)的大小(必须为512字节) 0x00, 0x02,
DB 1 ; 簇(cluster)的大小(必须为1个扇区) 0x01
DW 1 ; FAT的起始位置(一般从第一个扇区开始) 0x01, 0x00
DB 2 ; FAT的个数 0x02,
DW 224 ; 根目录的大小(一般设成224项) 0xe0, 0x00
DW 2880 ; 该磁盘的大小(必须是2880扇区) 0x40, 0x0b
DB 0xf0 ; 磁盘的种类(必须是0xf0) 0xf0
DW 9 ; FAT的长度(必须是9扇区)0x09, 0x00
DW 18 ; 1个磁道(track)有几个扇区(必须是18) 0x12, 0x00
DW 2 ; 磁头数(必须是2) 0x02, 0x00,
DD 0 ; 不使用分区,必须是0 0x00, 0x00, 0x00, 0x00
DD 2880 ; 重写一次磁盘大小 0x40, 0x0b, 0x00, 0x00,
DB 0,0,0x29 ; 意义不明,固定 0x00, 0x00, 0x29
DD 0xffffffff ; (可能是)卷标号码 0xff, 0xff, 0xff, 0xff
DB "HELLO-OS " ; 磁盘的名称(11字节) 0x48, 0x45, 0x4c, 0x4c, 0x4f,0x2d, 0x4f, 0x53, 0x20, 0x20, 0x20
DB "FAT12 " ; 磁盘格式名称(8字节) 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20
RESB 18 ; 先空出18字节

; 程序核心 开始地址:0x7c50

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で埋める命令

DB 0x55, 0xaa

asm.bat

1
..\z_tools\nask.exe ipl.nas ipl.bin ipl.lst
  • 编译输出列表文件ipl.lst。它是一个文本文件,可以用来简单地确认每个指令是怎样翻译成机器语言的。

makeimg.bat

1
..\z_tools\edimg.exe   imgin:../z_tools/fdimg0at.tek   wbinimg src:ipl.bin len:512 from:0 to:0   imgout:helloos.img
  • edimg.exe:作者自制的二磁盘映像管理工具
  • 该脚本作用:先读入一个空白的磁盘映像文件,然后在开头写入 ipl.bin的内容,最后将结果输出为名为helloos.img的磁盘映像文件。

run.bat

1
2
copy helloos.img ..\z_tools\qemu\fdimage0.bin
..\z_tools\make.exe -C ../z_tools/qemu

执行顺序asm→makeimg→run

ipl.lst

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
 1 00000000                                 ; hello-os
2 00000000 ; TAB=4
3 00000000
4 ORG 0x7c00 ; 指明程序的装载地址
5 00007C00
6 00007C00 ; 以下是标准FAT12格式软盘专用的代码 该段80字节
7 00007C00
8 00007C00 EB 4E JMP entry
9 00007C02 90 DB 0x90
10 00007C03 48 45 4C 4C 4F 49 50 4C DB "HELLOIPL" ; 启动区的名称可以是任意的字符串(8字?) 0x48, 0x45, 0x4c, 0x4c, 0x4f 0x49, 0x50, 0x4c
11 00007C0B 0200 DW 512 ; 每个扇区(sector)的大小(必须512字?) 0x00, 0x02,
12 00007C0D 01 DB 1 ; 簇(cluster)的大小(必须1个扇区) 0x01
13 00007C0E 0001 DW 1 ; FAT的起始位置(一般从第一个扇区开始) 0x01, 0x00
14 00007C10 02 DB 2 ; FAT的个数 0x02,
15 00007C11 00E0 DW 224 ; 根目录的大小(一般设成224项) 0xe0, 0x00
16 00007C13 0B40 DW 2880 ; 该磁盘的大小(必须是2880扇区) 0x40, 0x0b
17 00007C15 F0 DB 0xf0 ; 磁盘的种类(必须是0xf0) 0xf0
18 00007C16 0009 DW 9 ; FAT的长度(必须是9扇区)0x09, 0x00
19 00007C18 0012 DW 18 ; 1个磁道(track)有几个扇区(必?是18) 0x12, 0x00
20 00007C1A 0002 DW 2 ; 磁头数(必须是2) 0x02, 0x00,
21 00007C1C 00000000 DD 0 ; 不使用分区,必须是0 0x00, 0x00, 0x00, 0x00
22 00007C20 00000B40 DD 2880 ; 重写一次磁盘大小 0x40, 0x0b, 0x00, 0x00,
23 00007C24 00 00 29 DB 0,0,0x29 ; 意义不明,固定 0x00, 0x00, 0x29
24 00007C27 FFFFFFFF DD 0xffffffff ; (可能是)卷标号码 0xff, 0xff, 0xff, 0xff
25 00007C2B 48 45 4C 4C 4F 2D 4F 53 20 20 DB "HELLO-OS " ; 磁盘的名称(11字节) 0x48, 0x45, 0x4c, 0x4c, 0x4f,0x2d, 0x4f, 0x53, 0x20, 0x20, 0x20
00007C35 20
26 00007C36 46 41 54 31 32 20 20 20 DB "FAT12 " ;磁盘格式名称(8字节) 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20
27 00007C3E 00 00 00 00 00 00 00 00 00 00 RESB 18 ; 先空出18字节
00007C48 00 00 00 00 00 00 00 00
28 00007C50
29 00007C50 ; 程序核心 起始地址:0x7c50
30 00007C50
31 00007C50 entry:
32 00007C50 B8 0000 MOV AX,0 ; 初始化寄存器
33 00007C53 8E D0 MOV SS,AX
34 00007C55 BC 7C00 MOV SP,0x7c00
35 00007C58 8E D8 MOV DS,AX
36 00007C5A 8E C0 MOV ES,AX
37 00007C5C
38 00007C5C BE 7C74 MOV SI,msg
39 00007C5F putloop:
40 00007C5F 8A 04 MOV AL,[SI]
41 00007C61 83 C6 01 ADD SI,1 ; 使SI加1
42 00007C64 3C 00 CMP AL,0
43 00007C66 74 09 JE fin
44 00007C68 B4 0E MOV AH,0x0e ; 显示示一个文字
45 00007C6A BB 000F MOV BX,15 ; 指定字符颜色
46 00007C6D CD 10 INT 0x10 ; 调用显卡BIOS
47 00007C6F EB EE JMP putloop
48 00007C71 fin:
49 00007C71 F4 HLT ; 让CPU停止,等待指令
50 00007C72 EB FD JMP fin ; 无限循环
51 00007C74
52 00007C74 msg:
53 00007C74 0A 0A DB 0x0a, 0x0a ; 换行2次
54 00007C76 68 65 6C 6C 6F 2C 20 77 6F 72 DB "hello, world"
00007C80 6C 64
55 00007C82 0A DB 0x0a ; 换行
56 00007C83 00 DB 0
57 00007C84
58 00007C84 00 00 00 00 00 00 00 00 00 00 RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める命令
00007C8E 00 00 00 00 00 00 00 00 00 00
00007C98 00 00 00 00 00 00 00 00 00 00
00007CA2 00 00 00 00 00 00 00 00 00 00
00007CAC 00 00 00 00 00 00 00 00 00 00
00007CB6 00 00 00 00 00 00 00 00 00 00
00007CC0 00 00 00 00 00 00 00 00 00 00
00007CCA 00 00 00 00 00 00 00 00 00 00
00007CD4 00 00 00 00 00 00 00 00 00 00
00007CDE 00 00 00 00 00 00 00 00 00 00
00007CE8 00 00 00 00 00 00 00 00 00 00
00007CF2 00 00 00 00 00 00 00 00 00 00
00007CFC 00 00 00 00 00 00 00 00 00 00
00007D06 00 00 00 00 00 00 00 00 00 00
00007D10 00 00 00 00 00 00 00 00 00 00
00007D1A 00 00 00 00 00 00 00 00 00 00
00007D24 00 00 00 00 00 00 00 00 00 00
00007D2E 00 00 00 00 00 00 00 00 00 00
00007D38 00 00 00 00 00 00 00 00 00 00
00007D42 00 00 00 00 00 00 00 00 00 00
00007D4C 00 00 00 00 00 00 00 00 00 00
00007D56 00 00 00 00 00 00 00 00 00 00
00007D60 00 00 00 00 00 00 00 00 00 00
00007D6A 00 00 00 00 00 00 00 00 00 00
00007D74 00 00 00 00 00 00 00 00 00 00
00007D7E 00 00 00 00 00 00 00 00 00 00
00007D88 00 00 00 00 00 00 00 00 00 00
00007D92 00 00 00 00 00 00 00 00 00 00
00007D9C 00 00 00 00 00 00 00 00 00 00
00007DA6 00 00 00 00 00 00 00 00 00 00
00007DB0 00 00 00 00 00 00 00 00 00 00
00007DBA 00 00 00 00 00 00 00 00 00 00
00007DC4 00 00 00 00 00 00 00 00 00 00
00007DCE 00 00 00 00 00 00 00 00 00 00
00007DD8 00 00 00 00 00 00 00 00 00 00
00007DE2 00 00 00 00 00 00 00 00 00 00
00007DEC 00 00 00 00 00 00 00 00 00 00
00007DF6 00 00 00 00 00 00 00 00
59 00007DFE
60 00007DFE 55 AA DB 0x55, 0xaa

03. Makefile

没有找到文件,它会自动查找命令创建,故只要输入“make run”,它会首先执行“make img”,然后再启动模拟器。

Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# デフォルト動作

default :
../z_tools/make.exe img

# ファイル生成規則

ipl.bin : ipl.nas Makefile
../z_tools/nask.exe ipl.nas ipl.bin ipl.lst

helloos.img : ipl.bin Makefile
../z_tools/edimg.exe imgin:../z_tools/fdimg0at.tek \
wbinimg src:ipl.bin len:512 from:0 to:0 imgout:helloos.img

# コマンド

asm :
../z_tools/make.exe -r ipl.bin

img :
../z_tools/make.exe -r helloos.img

run :
../z_tools/make.exe img
copy helloos.img ..\z_tools\qemu\fdimage0.bin
../z_tools/make.exe -C ../z_tools/qemu

install :
../z_tools/make.exe img
../z_tools/imgtol.com w a: helloos.img

clean :
-del ipl.bin
-del ipl.lst

src_only :
../z_tools/make.exe clean
-del helloos.img