《30天自制操作系统》学习笔记 day1 - 机器语言到汇编语言

Hervey Lv3

十年前的读物

刚翻开这本书就被灰尘扑了一脸,看来这本书真的有些年代了。

一切的开始 - hello, world

今天的任务是让计算机识别我们写的代码,并能够在裸机上显示 hello, world

我们知道高级语言 (C/C++、Java、Python 等) 是不能够直接在裸机上运行的,需要经过编译转为二进制程序运行或使用解释器运行,特别的,Java 程序需要编译成为 Java 字节码,再通过 Java 虚拟机 (JVM) 运行。

因此,在没有任何编译器程序、仅有裸机的情况下,只有低级语言能够直接在裸机上运行,作者这里采用机器语言和汇编语言分别实现了 hello, world

机器语言实现 hello, world

书里首先给出了一个二进制程序作为引入,作为一个 21 世纪 20 年代 (现在是 2025 年) 的程序员,我选择使用 Visual Studio Code 搭配 Hex Editor 插件编写程序 helloos.img(作为一个前 CTFer,我也强烈安利 010 EditorWin Hex 等软件)。

好吧,感觉这样写要写半天还容易错,还是用脚本写程序吧… (事实证明就算用脚本也有可能写错)

gen.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
file = open('helloos.img', 'wb')

i = 0
while i < 0x168000:
if i == 0:
text = b'\xeb\x4e\x90\x48\x45\x4c\x4c\x4f\x49\x50\x4c\x00\x02\x01\x01\x00\x02\xe0\x00\x40\x0b\xf0\x09\x00\x12\x00\x02\x00\x00\x00\x00\x00\x40\x0b\x00\x00\x00\x00\x29\xff\xff\xff\xff\x48\x45\x4c\x4c\x4f\x2d\x4f\x53\x20\x20\x20\x46\x41\x54\x31\x32\x20\x20\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8\x00\x00\x8e\xd0\xbc\x00\x7c\x8e\xd8\x8e\xc0\xbe\x74\x7c\x8a\x04\x83\xc6\x01\x3c\x00\x74\x09\xb4\x0e\xbb\x0f\x00\xcd\x10\xeb\xee\xf4\xeb\xfd\x0a\x0a\x68\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x0a\x00\x00\x00\x00\x00'
elif i == 0x1FE:
text = b'\x55\xaa\xf0\xff\xff'
elif i == 0x1400:
text = b'\xf0\xff\xff'
else:
text = b'\x00'
file.write(text)
i += len(text)

file.close()

生成 helloos.img 之后,使用作者提供的工具链(在这里下载),将其装载到 qemu 之中,就能够 顺利地 看到 hello, world 字样了。

hello, world

使用汇编语言实现 hello, world

作者作者
你的机器语言确实很强
但还是太吃操作了
有没有什么简单又清晰的语言推荐一下
有的朋友,有的
像这么简单的语言还有一种
就是 汇编语言

为了提高代码的可读性和持续性,作者介绍了汇编语言实现 hello, world 的方式。

第一种实现方式其实还是机器语言的直译:

helloos1.nas
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

依旧和机器语言一样不具有可读性(其实就是机器语言),不过至少能够在一个屏幕上显示了。

第二种实现方式则更具有可读性,更像一个“程序”了:

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

; 以下这段是标准AFT2格式软盘专用的代码

DB 0xeb, 0x4e, 0x90
DB "HELLOIPL" ; 启动区的名称可以是任意的字符串(8字节)
DW 512 ; 每个扇区(sector)的大小(必须为512字节)
DB 1 ; 簇(cluster)的大小(必须为1个扇区)
DW 1 ; FAT的起始位置(一般从第一个扇区开始)
DB 2 ; FAT的个数(必须为2)
DW 224 ; 根目录的大小(一般设成224项)
DW 2880 ; 该磁盘的大小(必须是2880扇区)
DB 0xf0 ; 磁盘的种类(必须是0xf0)
DW 9 ; FAT的长度(必须是9扇区)
DW 18 ; 1个磁道(track)有几个扇区
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-$ ; 填写0x00,直到 0x001fe
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

笔记

汇编指令 全称 作用
RESB reseve byte 将指定的地址空出,并在空出的地址上自动填入 0x00
DB define byte 往文件里直接写入 1 个字节 / 一串字符
DW define word 往文件里直接写入 2 个字节
DD define double-word 往文件里直接写入 4 个字节
  • $ 目前可以理解为指代当前行的字节数(具体含义后续章节会补充)

后记

就这样,第一天的学习在大段的的十六进制码中结束了,说说我的感受吧。

硬件发展更迭好快

这本书里使用 软盘 装载操作系统,“这是什么?”或许是大部分出生在 21 世纪的人(包括我)看到这两个字的第一反应,毕竟我们只在保存按钮和一些视频中看见过软盘的样貌,现在容量更大、存取速度更快的存储设备已经完全取代了软盘、光盘等等媒介。

在我们的父母甚至祖父母那一辈却不然,他们经历了计算机在国内引进和发展的过程,亲眼见证了计算机体积的缩小,见证了制造技术的不断改进,见证了移动设备的兴起,或许他们读这本书的感受会和我们不一样。

而在我们之后出生的人,他们接触到的是一个高度发展的信息时代,旧的设备几乎被完全淘汰,新的设备不断更迭,很多人甚至不会还使用电脑就会使用手机了(其实我们这辈就有),他们又会如何理解和认识软盘之类的设备, 又会如何看待这些接近硬件层面的技术呢?

低级语言好麻烦

今天这三个程序的编写(仅仅只是显示一个 Hello, world )就耗费了一下午时间,而且还是在有完整工具链和现代化工具(甚至使用 Python 脚本辅助)的情况下实现的,很难想象在半个多世纪以前,科学家们是如何一步步实现如此庞大的计算机系统的,又是如何调试运行的。

学习这些底层技术知识,重走来时路,或许是我们感受前人智慧的一种好方法,万一有一天我的经历也会成为他人阅读的历史呢?

  • 标题: 《30天自制操作系统》学习笔记 day1 - 机器语言到汇编语言
  • 作者: Hervey
  • 创建于 : 2025-03-02 12:56:52
  • 更新于 : 2025-03-04 02:07:40
  • 链接: https://herveyb3b4.github.io/2025/03/02/OSASK/OSASK-day1/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
目录
《30天自制操作系统》学习笔记 day1 - 机器语言到汇编语言