你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益:
- 了解大厂经验
- 拥有和大厂相匹配的技术等
希望看什么,评论或者私信告诉我!
一、背景
其实也没有啥背景。
最主要的原因就像 《30天自制操作系统》一书作者说的那样,写一个操作系统,仅仅想想就是一件特别有趣的事情呢。一两年前曾经入手开始写过,但慢慢的就不了了之了。现在又有这个想法了,准备一直干下去,最终写一个操作系统出来,算是程序员生涯的一份礼物。
其次的原因,是因为我也认为未来初级程序员的岗位会越来越少,借助 LLM 人人都是初级程序员可能会变成现实。这个时候专业性和底层就会越来越重要
二、汇编介绍
《30天自制操作系统》一书中第二课的汇编语言,注释如下:
; hello-os
; TAB=4
; bootloader code
ORG 0x7c00 ; 指明程序装载地址 出厂的时候BIOS就被组装在电脑主板上的ROM单元里。电脑厂家在BIOS中预先写入了操作系统开发人员经常使用的一些程序
; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code
JMP entry
DB 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扇区1440*1024/512)
DB 0xf0 ; 磁盘类型(必须为0xf0)
DW 9 ; FAT的长度(必??9扇区)
DW 18 ; 一个磁道(track)有几个扇区(必须为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: ;0x7c50
MOV AX,0 ; 初始化寄存器 MOV:赋值
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
MOV ES,AX
MOV SI,msg
putloop:
MOV AL,[SI] ; [] 表示内存,表示把 SI对应的内存地址上数据的1个字节的内容读入到 AL 中。 MOV的数据传送源和传送目的地不仅可以是寄存器或常数,也可以是内存地址。 MOV会自动要求源数据和目标数据位数一致
ADD SI,1 ; 给SI加1
CMP AL,0
JE fin ; 如果结果相等则跳转到指定地址,如果不等则不跳转
MOV AH,0x0e ; 显示一个字符 INT 0x10, AH = 0xE -- display char,这是调用 BIOS 的 “Teletype Output” 功能,用于在屏幕上显示一个字符,并推进光标
MOV BX,15 ; 指定字符颜色
INT 0x10 ; 调用显卡显示文字,INT 0x10 = Video display functions (including VESA/VBE) INT软件中断指令
JMP putloop
fin:
HLT ; 让CPU停止,等待指令
JMP fin ; 无限循环
msg: ;0x7c74
DB 0x0a, 0x0a ; 换行两次
DB "hello, world"
DB 0x0a ; 换行
DB 0
RESB 0x7dfe-$ ; 填写0x00填充到0x7def, 有了 ORG,$代表将要读入的内存地址
DB 0x55, 0xaa
; AX —— accumulator,累加寄存器 0-7位的低8位成为AL,8-15位的高8位称为 AH
; CX —— counter,计数寄存器
; DX —— data,数据寄存器
; BX —— base,基址寄存器 通常在内存寻址中用来存放基地址。它与源索引SI和目的索引DI寄存器结合,可以用于访问数组或其他数据结构。
; SP —— stack pointer,栈指针寄存器 SP寄存器指向当前栈的顶部。在执行函数调用、参数传递、局部变量分配和函数返回时,栈指针会相应地增加或减少。
; BP —— base pointer,基地址指针寄存器 通常用于访问堆栈中的局部变量和函数参数。在栈帧中,BP通常指向帧的起始位置。
; SI —— source index,源变址寄存器 通常用于字符串操作和数组处理中,指向源数据的位置
; DI —— destination index,目的变址寄存器 同样用于字符串操作和数组处理,但它指向目标数据的位置
; 这些都是 16 位寄存器,所以可以存储16位的二进制. 按照机器语言中寄存器的编号顺序排列的
; 指令编码:操作码 opcode 和 操作数 operand 构成
; CPU中的8个8位寄存器,具体为:
; AL——累加寄存器低位(accumulator low)
; CL——计数寄存器低位(counter low)
; DL——数据寄存器低位(data low)
; BL——基址寄存器低位(base low)
; AH——累加寄存器高位(accumulator high)
; CH——计数寄存器高位(counter high)
; DH——数据寄存器高位(data high)
; BH——基址寄存器高位(base high)
; 段寄存器
; 这些段寄存器都是16位寄存器。
; ES——附加段寄存器(extra segment)
; CS——代码段寄存器(code segment)
; SS——栈段寄存器(stack segment)
; DS——数据段寄存器(data segment)
; FS——没有名称(segment part 2)
; GS——没有名称(segment part 3)
重点关注一下几个点:
- 通过汇编开发程序,被成为 Bootloader Code 具体 Bootloader 是什么以及在计算机启动过程中有啥作用,这篇文章有较为详细的介绍
- 程序的装在位置什么是:0x7c00
这一块是 IBM 大叔们规定的,It should also be noted that your bootloader code is loaded and running in memory at physical addresses 0x7C00 through 0x7DFF. - INT 0x10, MOV AH 0xE 表示 display char。这些都是在调用 BIOS function
- BIOS 在这篇文章中也有介绍。
这里再补充一下:BIOS 是计算机出厂时就被组装在电脑主板上的ROM单元里。电脑厂家在BIOS中预先写入了操作系统开发人员经常使用的一些程序。
三、Makefile
Makefile 是一个文本文件,用于控制自动化构建过程,特别是在软件开发领域。它是由 make 命令读取的脚本,用来指导编译器和链接器如何构建源代码、库和其他依赖项。
Makefile 通常包含以下元素:
- 目标(Targets):Makefile 中的目标通常是最终要生成的文件,比如可执行程序或库文件。
- 依赖关系:每个目标可以有零个或多个依赖项,这些依赖项是该目标所依赖的其他目标和文件的列表。
- 命令:当目标的依赖项比目标本身更新时,需要执行的命令列表,例如编译器的编译指令等。
- 变量:用于简化 Makefile 的维护和增强其可读性的名称/值对。
- 自动变量和模式规则:用于进一步抽象常见的构建任务。
- 隐含规则:make 提供了一些内置的规则和变量,可用于常见的目标类型,如 .o 文件和可执行文件。
Makefile 的语法相对简单,但是非常强大且灵活,可以适应各种复杂的构建场景。对于大型项目来说,手工编译每一个模块不仅费时而且容易出错,而 Makefile 可以帮助自动化这一过程,确保项目的各个部分按照正确的顺序和规则进行编译和链接。
在实际的开发环境中,尤其是涉及 C/C++ 语言的项目中,Makefile 被广泛使用。此外,许多现代构建系统和包管理器(如 CMake、GNU Build System 等)也支持或生成为旧版 make 系统编写的 Makefile。
四、BIOS 扩展
BIOS(基本输入输出系统)是一种固件,它既不属于纯粹的软件也不完全是硬件。固件是介于软件和硬件之间的一种特殊形式,它通常被编程到计算机主板上的一块闪存或EPROM芯片中。BIOS负责在计算机启动时初始化硬件,并提供一个到操作系统的桥梁,使得计算机能够加载操作系统。虽然BIOS在功能上类似于软件,但它的存储和执行方式又与硬件相似,因此它被看作是一种固件。
BIOS(基本输入输出系统)的概念最初是在1975年由Gary Kildall为Intel 8080微处理器设计的CP/M操作系统(Control Program/Monitor)的一部分而产生的。以下是BIOS发展的一些关键点:
- CP/M操作系统:Gary Kildall创建的CP/M操作系统需要一个方法来与不同的硬件进行通信。为了解决这个问题,他设计了一个BIOS,它包含了一系列底层硬件接口的例程,这些例程可以被CP/M调用以执行输入输出操作。
- IBM PC的推出:1981年,IBM推出了第一台个人计算机IBM PC。为了使软件开发变得更加容易,IBM决定在其PC上使用BIOS来提供一个标准的硬件接口。这样,软件开发者就可以编写应用程序,而不必担心与各种硬件的直接交互。
- BIOS的作用:在IBM PC中,BIOS负责在计算机启动时执行POST(电源自检)来检查硬件配置,初始化硬件组件,并提供一个引导加载程序来从磁盘或其他存储设备加载操作系统。
- 兼容性和标准化:随着IBM PC及其兼容机的普及,BIOS成为行业标准。其他硬件制造商开始为他们的主板编写兼容的BIOS,以保持与IBM PC软件的兼容性。
- BIOS的发展:随着时间的推移,BIOS的功能不断扩展,以支持新的硬件技术和功能。尽管后来UEFI(统一可扩展固件接口)开始逐渐取代传统的BIOS,但BIOS的概念和基本功能仍然在现代计算机系统中发挥着作用。
BIOS的产生是计算机历史上一个重要的里程碑,它为硬件和软件之间的标准化交互奠定了基础,并且极大地推动了个人计算机的普及和发展。
五、总结
通过汇编语言的介绍,作者展示了操作系统开发的基础,包括Bootloader Code的重要性和BIOS在计算机启动过程中的作用。Makefile的自动化构建过程和BIOS的历史发展也被详细阐述,为读者提供了计算机系统开发的深入理解。