第二天-汇编与Makefile
汇编语言学习与Makefile入门
一、汇编学习
汇编核心程序
; hello-os
; TAB=4
ORG 0x7c00 ; 指明程序装载地址
JMP entry
; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code
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:
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 ; 换行两次
DB "hello, world"
DB 0x0a ; 换行
DB 0
RESB 0x7dfe-$ ; 填写0x00直到0x001fe
DB 0x55, 0xaa
指令汇总
-
ORG:origin,告诉nask,本程序被装载在0x7c00处
- 为啥是这个地方?因为BIOS默认会启动0x7c00~0x7dff处一共512字节的程序,上述汇编编译完成后一共512字节
-
DB:data byte,意思就是此处有1个字节的内容,比如DB 0x90,此处有1个字节的内容是0x90(十六进制表示)
-
DW:data word,意思就是此处有2个字节的内容
-
DD:data double-word,意思就是此处有4个字节的内容
-
MOV:move,移动的意思,但是在汇编里面就是赋值的意思,比如MOV AX,0相当于给寄存器AX赋值0
-
ADD:add,做加法,ADD SI,1即SI=SI+1
-
JMP:jump,表示跳到指定的内存地址,或者指定label,label本质也是指定地址
-
CMP:compare,比较,CMP AL,0即比较AL寄存器中值是否为0
-
JE:jump if equal,如果等于就跳转,一般配合CMP使用
-
INT:interrupt,中断,中断比较复杂,后面专门会讲,此处带一下概念:中断CPU正在做的事情而去处理发出中断的事件比如鼠标移动
-
HLT:halt,停止,意思是让CPU空闲下来,不让CPU空转
-
RESB:reserve byte,预留字节,比如RESB 10表示此处往后预留10个字节,初始化为0
模块1分析
ORG 0x7c00 ; 指明程序装载地址
JMP entry
-
ORG伪命令
-
ORG是Origin的缩写:起始地址源。在汇编语言源程序的开始通常都用一条ORG伪指令来实现规定程序的起始地址。如果不用ORG规定则汇编得到的目标程序将从0000H开始
-
cpu在接收到int 0x19中断后,调用中断服务程序,将软盘第一扇区(512B)的程序加载到0X07c00这个地址上,操作系统BIOS会去执行0x7c00往后的512字节的指令
-
因为这段程序将会加载到0x07c00上,所以使用org 0x7c00来规范代码(代码使用相对地址时使用)。而不是使用org 0x7c00,程序才会加载到0x07c00上
-
使用了 org后,entry = entry + 0x7c00
-
-
0x7c00的含义
-
内存中不是所有的内存都可以供应用程序使用的
- 如:0xf0000好地址存BOIS程序不能用
-
程序中ORG的指令的值为启动区内容的装载地址:0x00007c00 - 0x00007dff
-
这个地址是IBM硬件上做好的规定
-
-
JMP
- 跳转指令, 相当于c语言的 goto 命令
-
entry:
- 一个标号,JMP跳转的目的地,类似于 goto语句要跳转的标识符
什么是标号?
- 所有的标号的值都是代表它出现的内存地址, 由编译器根据ORG指令计算出来的
- 如 MOV AX, entry
- 表示将entry的地址0x7c50 存储到AX寄存器中
寄存器介绍
- 寄存器; 存储电路,相当于c语言的变量
16位寄存器
- AX
- 累加寄存器, accumulator
- AL
- 累加寄存器的低位( 0 -7 )
- AH
- 累加寄存器的高位 ( 8 - 15 )
- BX
- 基址寄存器, base
- BL
- BH
- CX
- 计数寄存器, counter
- CL
- CH
- DX
- 数据寄存器, data
- DL
- DH
- SP
- 栈指针寄存器, stack pointer
- BP
- 基址指针寄存器, base pointer
- SI
- 源变址寄存器, source index
- DI
- 目的变址寄存器, destination index
32位的寄存器
- EAX
- EBX
- ECX
- EDX
- ESP
- EBP
- ESI
- EDI
段寄存器 - 16位
- ES
- 附加段寄存器,extra segment
- CS
- 代码段寄存器, code segment
- SS
- 栈段寄存器, stack segment
- DS
- 数据段寄存器, data segment
- FS
- GS
模块2 - 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code
- 这是固定的,用于格式化软盘
模块3 - 赋值操作
entry:
MOV AX,0 ; 初始化寄存器
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
MOV ES,AX
MOV SI,msg
-
MOV 指令
-
赋值指令(copy操作)
-
MOV指令的源地址和目的地址,可以是寄存器、常数、内存地址
-
-
汇编语言保留字
- BYTE
- MOV BYTE [678] 123
- 用内存 678 号地址 保存 123这个数值,产犊为一个字节大小
- MOV BYTE [678] 123
- WORD
- MOV WROD [678] 123
- 这是双字节16位指令,会将123写入相邻的678,679两个地址(即两个字节大小)
- 相邻是指往地址增加方向
- MOV WROD [678] 123
- DWORD
- 就是4个字节大小
- BYTE
-
MOV指令规则
- 源数据和目的数据必须位数相同
MOV BX DX
MOV AL, BYTE [BX]
==
MOV AL BYTE [SI]
模块4 - 在屏幕显示一个字节的内容, 这里是一个循环,不断执行 putloop
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
-
MOV AL, [SI]
-
[]代表内存的意思
-
内存
- 对于CPU而言,属于外部存储器
- 当CPU向内存读取数据
- CPU要通过一部分引脚,向内存中发送电信号,告诉内存把相应位置的数据通过引脚发送到CPU
-
只能用BX,BP,SI, DI 四个寄存器指定内存地址
-
-
ADD 指令
-
加法指令
-
ADD SI I 等价于 SI = SI+1
-
-
CMP
-
比较指令
-
CMP a, 3 等价于 if(a ==3)
-
-
JE
-
条件跳转指令 - jump if equal
-
CMP AL, 0 JE fin 等价于 if(AL == 0) goto fin; //fin是个标号
-
-
INT 指令
-
软件中断指令 interrupt
- 电脑中BIOS装在电脑主板的ROM中,是预先写入的基本输入输出系统,一些系统开发程序经常用到的程序,而INT就是用来调用这些函数的指令
- 如 INT 0x10
- 调用16 号函数,用于控制显卡
- 如 INT 0x10
- 电脑中BIOS装在电脑主板的ROM中,是预先写入的基本输入输出系统,一些系统开发程序经常用到的程序,而INT就是用来调用这些函数的指令
-
要显示内容到屏幕,需要先把内容写入寄存器,然后在调用 INT 0x10去调用显卡
-
-
HLT
-
让CPU停止动作的指令 - halt
-
让CPU进入待机状态,等待外界变化(键盘,鼠标等)后唤醒,继续执行程序
-
模块5 - 让CPU空转
fin:
HLT ; 让CPU停止,等待指令
JMP fin ; 无限循环
模块6 - 要显示的字符
msg:
DB 0x0a, 0x0a ; 换行两次
DB "hello, world"
DB 0x0a ; 换行
DB 0
RESB 0x7dfe-$ ; 填写0x00直到0x001fe
DB 0x55, 0xaa
-
有了 ORG命令之后,$的含义发生变化
-
原:输出文件的第几个字节
-
现:要读入的内存地址
-
总结
- 汇编语言是按顺序执行,除非出现跳转语句
- 所以上述代码执行流程:初始化寄存器,调用BIOS显示msg里面的内容:hello world,然后HLT住CPU
制作启动区(helloos4)
-
根据上述的启动区的汇编代码,制作512字节的启动区
-
源文件为上述的汇编核心代码ipl.nas, 编译汇编代码成二进制代码, asm.bat
-
输出文件名为 ipl.bin ,是汇编代码编译后的机器代码
-
列表文件为ipl.lst,ipl.lst是每句汇编指令和机器指令的对照
-
..\z_tools\nask.exe ipl.nas ipl.bin ipl.lst
-
-
以二进制代码制作磁盘映像文件
-
..\z_tools\edimg.exe imgin:../z_tools/fdimg0at.tek wbinimg src:ipl.bin len:512 from:0 to:0 imgout:helloos.img
-
-
在虚拟器运行映像文件
-
-
可以在VMware虚拟机中,给现有的虚拟机添加软盘和文件去运行,[参考文章]((149条消息) VMWare虚拟机启动img文件_vmware img 启动系统_我要出家当道士的博客-CSDN博客)
-
现在的流程
- 编写asm.bat编译汇源源码文件,得到二进制可执行文件
- 二进制代码制作磁盘映像文件
- 启动 console
- 输入 asm 编译
- 输入making 制作镜像文件
- 输入run 运行镜像文件
二、 Makefile 入门
- makefile可以解决上述的繁琐的批处理方式
- 一个批处理文件,实现将源码编译成可执行文件说明书
简单的Makefile文件
-
# 文件生成规则 ipl.bin:ipa.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
-
代码解释
-
是注释符号, \ 是续行符号
-
ipl.bin:ipa.nas Makefile
-
表示要制作文件ipl.bin,先检查ipl.nas和Makefile是否准备好,如果是在,则makefile工具就会自动执行下一行
-
为了使用make.exe让Makefile发挥作用,做一个make.bat从命令行运行这个makefile工具,在tolnet/z_new_w文件夹下有一个示例
-
打开一个命令行窗口,输入 make -r ipl.bin, make.exe就会启动
- 它先读取Makefile文件,寻找制作ipl.bin的方法,它从Makefile中找到并执行其中的命令,生成ipl.bin
-
输入 make -r helloos.img
- 也是启动make.exe去执行,然后按照命令去执行,生成helloos.img文件
-
如果在没有 ipl.bin文件,直接输入 make -r helloos.img
- 它会先去试图生成helloos.img,发现ipl.bin还没存在,则去Makefile中寻找方法去生产ipl.bin,再回来生成helloos.img
-
如果已经有了这两个文件,再执行make -r helloos.img, make.exe会先判断输入文件有没有变化,有则重新编译执行;如果是没有改变,Makefile就是什么都不干
-
-
如何执行
- 启动一个 console
- 输入 make -r ipl.bin
- 输入 make -r helloos.img
总结
- 我们可以在Makefile中增加内容,就可以把批处理文件替换, 直接输入 make 标号即可
# デフォルト動作
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
-
Makefile会自动跳过没有必要的指令
- 直接 make asm、make img、make run,它就会自动执行相应的指令
-
make clean
- 删除最终结果(这里是hellos.img)以外的所有中间文件,将磁盘整理干净
-
make src_only
- 把源程序意外的所有文件都删除干净
-
通过default,设置不带make参数时的默认指令
运行
- !cons_st打开命令行窗口
- 依次输入 make asm, make img, make run
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现