第二天-汇编与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这个数值,产犊为一个字节大小
    • WORD
      • MOV WROD [678] 123
        • 这是双字节16位指令,会将123写入相邻的678,679两个地址(即两个字节大小)
        • 相邻是指往地址增加方向
    • DWORD
      • 就是4个字节大小
  • 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去调用显卡

  • 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

image-20230330010028199

posted @   bingekong  阅读(96)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示