00. 准备

01 .二进制编辑器

Bz - c.mos (vcraft.jp)下载,解压使用Bz1621.lzh,双击Bz.exe打开二进制编辑器

输入:0到168000行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
           +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0000:0000 EB 4E 90 48 45 4C 4C 4F 49 50 4C 00 02 01 01 00
0000:0010 02 E0 00 40 0B F0 09 00 12 00 02 00 00 00 00 00
0000:0020 40 0B 00 00 00 00 29 FF FF FF FF 48 45 4C 4C 4F
0000:0030 2D 4F 53 20 20 20 46 41 54 31 32 20 20 20 00 00
0000:0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0050 B8 00 00 8E D0 BC 00 7C 8E D8 8E C0 BE 74 7C 8A
0000:0060 04 83 C6 01 3C 00 74 09 B4 0E BB 0F 00 CD 10 EB
0000:0070 EE F4 EB FD 0A 0A 68 65 6C 6C 6F 2C 20 77 6F 72
0000:0080 6C 64 0A 00 00 00 00 00 00 00 00 00 00 00 00 00
...
0000:01F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA
0000:0200 F0 FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00
...
0000:1400 F0 FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00
...
0016:7FF0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

显示:0到168000行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
           0123456789ABCDEF
0000:0000 .N.HELLOIPL.....
0000:0010 ...@............
0000:0020 @.....)....HELLO
0000:0030 -OS FAT12
0000:0040 ................
0000:0050 .......l.....tl.
0000:0060 ....<.t.........
0000:0070 ......hello, wor
0000:0080 ld..............
...
0000:01F0 ..............U.
0000:0200 ................
...
0000:1400 ................
...
0016:7FF0 ................

中途或者写完后,可以另存为helloos.img,该文件占用 1474560(1440*1024) 字节.

打开 tolset 文件夹,在里面新建 helloos0 文件夹,将 helloos.img 放入并新建两个文件: install.batrun.bat

run.bat

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

解释:

  • 第一行 copy:cmd命令 该行将 helloos.img 复制到 qemu 并重命名为 fdimage0.bin
  • 第二行 运行PC模拟器QEMU,让代码在上面跑,模拟器在光盘里 ./tolset/z_tools 目录下

install.bat

1
..\z_tools\imgtol.com w a: helloos.img

解释:

  • helloos.img 刻录到软盘 a w :写 a:软盘盘符

双击 run.bat 运行显示:

1
hello, world

02 .仅使用DB和RESB的汇编

汇编代码需要编译,这里采用作者自制的编译器 nask

超长源代码

1
2
3
4
5
6
7
DB	0xeb, 0x4e, 0x90, 0x48, 0x45, 0x4c, 0x4c, 0x4f
DB 0x49, 0x50, 0x4c, 0x00, 0x02, 0x01, 0x01, 0x00
DB 0x02, 0xe0, 0x00, 0x40, 0x0b, 0xf0, 0x09, 0x00
DB 0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
DB 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x29, 0xff
...
DB 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

asm.bat

1
..\z_tools\nask.exe helloos.nas helloos.img

运行上面命令,可以得到 helloos.img

使用DB和RESB简化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
DB	0xeb, 0x4e, 0x90, 0x48, 0x45, 0x4c, 0x4c, 0x4f
DB 0x49, 0x50, 0x4c, 0x00, 0x02, 0x01, 0x01, 0x00
DB 0x02, 0xe0, 0x00, 0x40, 0x0b, 0xf0, 0x09, 0x00
DB 0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
DB 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x29, 0xff
DB 0xff, 0xff, 0xff, 0x48, 0x45, 0x4c, 0x4c, 0x4f
DB 0x2d, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x46, 0x41
DB 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00
RESB 16
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, 0x0a, 0x0a, 0x68, 0x65
DB 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72
DB 0x6c, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00
RESB 368
DB 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB 4600
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB 1469432
  • DB:往文件里面输入一个字节
  • RESB:”reserve byte”的缩写,RESB XX 从现在的地址开始空出 XX 个字节,nask编译时把空出的填充为 0x00

03 .多指令汇编

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
; hello-os
; TAB=4

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

DB 0xeb, 0x4e, 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字节

; 程序主体 该段36字节

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

; 信息显示部分 该段512-36-80字节

DB 0x0a, 0x0a ; 2个换行
DB "hello,my name is hello-os.this is my first os program."
DB 0x0a ; 换行
DB 0

RESB 0x1fe-$ ; 填写0x00,直到0x001fe 即510

DB 0x55, 0xaa ; 第511 512字节

; 以下是启动区以外部分的输出

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

  • DB:可以直接写字符串
  • DW:”define word” ,写2个字节
  • DD:”define double word”,写4个字节
  • 第41行,RESB 0x1fe-$ 美元符号 $ 是个变量,在该程序中,我们已经在前面输出了132个字节,所以这里的 $ 就是132,因此 0x1fe - $ 就是378 连续输出3780x00。用它是因为要保证第510字节开始地址是55AA,如果显示信息如 “hello, world” 的有长度变化,不用这个 $ 自动计算,就会出错。

问题:DB 0xeb, 0x4e, 0x90 是什么意思?

  • 可写为

    1
    2
    DB 0xeb, 0x4e
    DB 0x90
  • 根据day2的代码 上面第一行代码 DB 0xeb, 0x4e 被改为了 JMP entry ,为什么?

    0xeb 是 x86 汇编指令 JMP SHORT,而 NASK 汇编把 JMP SHORT 简写为 JMP,0x90是x86汇编里的 NOP(空指令),也就是说 0xeb 0x4e 0x90 和汇编代码 JMP 0x4e; NOP; 是等价的

  • 0x4e 从哪里来?

    0x4e 是转移的位移量,把书翻到第24页数一下从 0x90 开始到第25页的 resb 18 一共占的字节数,正好是 0x4e($78_o$)个

  • 从开头到主体有 80 个字节(0x50)为什么 JMP 0x4e

    0x4e0x50-2。减2是因为 pc 指针已经指向了下一句 NOP 指令前面,所以偏移量要减去 JMPentry 的机器码 (0xeb0x4e) 所占的内存空间

  • 为什么要 0x55 0xAA ?

    见书P26末-P27始,计算机读软盘以512字节为单位,软盘512字节为一个扇区,并且读到的第一个扇区为启动扇区,检查第一个扇区最后两个字节是否为0x55 0xAA 如果不是则认为无启动程序,报错,是则执行。

    所以,虽然在第一个扇区程序从开头写到 RESB 0x1fe-$ 写了510个字节,但是加上0x55 0xAA 就是512字节,作为启动程序。

参考资料:

《30天自制操作系统》笔记3 — (Day2 上节)完全解析文件系统

第一章例子的第一行(DB 0xeb, 0x4e, 0x90)是什么意思?【30天自制操作系统吧】