自制操作系统笔记-第2章

helloos.nas节选

  ORG 0x7c00  ;指明程序的装载地址
;以下记述用于标准FAT12格式软盘

JMP entry    ; 0xeb, 0x4e, 
DB 0x90      ; 0x90

DB "HELLOIPL" ;引导扇区(启动区)的名称(8字节)
DW 512 ;一个扇区(sector)的大小(必须是512字节)
DB 1 ; 簇(cluster)的大小(必须是1个扇区)
DW 1 ; FAT的起始位置(一般从第1扇区开始)
DB 2 ; FAT个数(必须为2)
DW 224 ; 根目录的大小(一般为224项)
DW 2880 ; 此驱动器的大小(必须为2880扇区)
DB 0xf0 ; 磁盘种类(必须为0xf0)
DW 9 ; FAT的长度(必须为9个扇区)
DW 18 ; 1个磁道(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直到0x7dfe,程序最开始的ORG 0x7c00表示程序加载到内存中的0x7c00, ,0x1fe转为十进制是510, 0x7c00 + 0x1fe 就是 0x7dfe, 至于为什么是0x1fe第一章说过了,为什么是7c00本章下面介绍了。

    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

 

 

 

 

ORG 源于英文origin ,源头、起点,把程序装载到内存中的指定地址。有了它,$符的含义就随之变化,不再是输出文件的第几个字节,而代表将要读入的内存地址。我理解,没写ORG时,$就代表镜像文件从开头到当前行的字节数,有了ORG,就代表的是内存的地址号。

JMP 源于英jump,即跳转,用法:

JMP 标签名

MOV 源于英文move,意为移动, 功能为赋值,非常重要,理解了它就理解了汇编语言的一大半。

MOV AX,0 相当于 AX=0;

MOV SS,AX 相当于 SS=AX;

执行MOV SS,AX后,AX的值不变

 

CPU里有一种名为寄存器的存储电路,相当于机器语言中的变量,具有代表性的有以下8个:

  • AX  accumulator 累加寄存器 ,用来进行各种计算   为分AH AL
  • CX counter 计数寄存器,为方便计数 分为 CH CL
  • DX data 数据寄存器,分为DH DL
  • BX base 基址寄存器,适合做为计算内存地址的基点 分为 BH BL
  • SP stack pointer 栈指针寄存器
  • BP base pointer 基址指针寄存器
  • SI source index 源变址寄存器
  • DI destination index 目的变址寄存器

这些都是16位寄存器,这个顺序是按机器语言中寄存器的编号顺序排列的,X表示扩展(extend),因为之前CPU寄存器是8位的,后来变为16位,所以在寄存器名后面加个X,

在16位寄存器名字前面加上一个E(源于Extend)就是32位寄存器的名字了:EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI。

EAX的32位中的低16位是与AX共用的,而高16位没有名字也没有编号。

32位CPU也只能存储32字节,(32/8=4字节,4字节/寄存器*8个寄存器=32字节)。

CPU里还有6个16位的段寄存器:

  • ES 附加段寄存器 extra segment
  • CS 代码段寄存器 code segment
  • SS 栈段寄存器 stack segment
  • DS 数据段寄存器 data segment
  • FS 没有名称 segment part2
  • GS 没有名称 segment part3

MOV SI,msg ?

JMP entry ,  entry是标号,每个标号对应的数字由汇编语言编译器根据ORG指令计算出来的,“标号的地方对应的内存地址”就是标号的值 。书中例子entry 相当于0x7c50。

MOV AX,entry   会把0x7c50代入到AX寄存器里。

MOV AL, [SI]  方括号代表内存,

 

对CPU来说,内存是外部存储器,CPU与内存之间的电信号交换,不仅为了存取数据,程序本身也在内存里。程序必须放在内存里。CPU在执行机器语言时,必须从内存中一个命令一个命令的读取程序,顺序执行。

MOV 指令的数据传送源和传送目的地 不仅可以是寄存器或常数,也可以是内存地址。这时我们就用[]表示内存地址。

BYTE,WORD,DWORD都是汇编语言保留字。

MOVE BYTE [678],123 用内存的678号地址来保存“123”这个数值。即在内存地址678号存储01111011(即123);

MOVE WORD [678],123 将123转为0000 0000 0111 1011,将0111 1011存到内存地址678号中,将0000 0000 存到内存地址679中。

汇编语言里指定内存地址时,要用下面方式:

数据大小 [地址]

数据大小为BYTE,使用的存储单元就只是地址所指定的字节,为WORD则相邻的一个字节也会成为这个指令的操作对象。如果为DWORD,则相邻的三个字成为操作对象。相邻指地址增加的方向的相邻。 

内存地址的指定方法,不仅可以使用常数,还可使用寄存器,如 BYTE [SI]、WORD [BX]

只有BX,BP,SI,DI这几个寄存器可以用来指定内存地址,(因为CPU没有对应的电路,也就是没有对应的机器语言),所以想把DX内存里的内容赋值给AL的时候, 这样写:

MOV BX, DX

MOV AL, BYTE [BX]

--------------------------------------------------------------------------------------------------------------------------------------

MOV指令有个规则,即源数据和目的数据必须位数相同,即向AL里代入的也只有BYTE,那就可以省略BYTE,

MOV AL, BYTE [SI] 可简写为 MOV AL [SI]

-----------------------------------------------------------------------------------------------------------------------------------

 ADD 加法指令,ADD SI,1 就相当于 SI=SI+1.

CMP  比较指令(compare),即if语句的一部分,如if(a ==3) { ... },对a和3比较,翻译成汇编语言必须先写CMP a,3 告诉CPU比较的对象,然后下一步再写“如果二者相等需要做什么”。

JE是条件跳转指令之一(jump if equal),即根据比较结果决定 是否跳转,如相等则跳转到指定地址,否则继续执行下一条指令。

-----------------------------------------------------------------------------------------------------------------------------------

 INT是软件中断指令(interrupt,中途打断)。暂时先看作一个函数调用。

INT 0x10 ,INT后面是个数字,使用不同数字可以调用 不同函数,0x10即16号函数,功能是控制显卡。

https://wenku.baidu.com/view/9be1ae2cabea998fcc22bcd126fff705cc175c1d.html 查询BIOS 的中断相关信息,得知:

  • AH=0x0e; (有的地方也写做0EH ,H表示HEX,十六进制)
  • AL=字符;
  • BH=0;       (页码)
  • BL=color code;  (需图形模式)
  • 返回值: 无
  • 注: beep、back space、CR、LF都会被当做控制字符处理

所以,按这里所写的步骤往寄存器里代入各种值,再调用 INT 0x10,就能顺利在屏幕上显示一个字符。目前颜色只能是白色。

-------------------------------------------------------------------------------------------------------------------------------

 HLT 让CPU停止动作的指令(halt 停止),并不是彻底停止(除非断电),而是让CPU进入待机状态,只要外部发生变化,如按键,动鼠标CPU就会醒来,

fin:
    HLT 
    JMP fin

所以,这里有没有HLT都会是无限循环,但是如果没有HLT,CPU就会不信的执行JMP指令,

--------------------------------------------------------------------------------------------------------------------------------

 用C语言改写后的helloos.nas程序节选:

entry:

  AX = 0;

  SS = AX;

  SP =  0x7c00;

  DS = AX;

  ES = AX;

  SI = msg;

putloop:

  AL = BYTE [SI];

  SI = SI + 1;

  if( AL == 0 )  { goto fin; }

  AH = 0x0e;

  BX = 15;

  INT = 0x10;

  goto putloop;

fin:

  HLT;

  goto fin;

------------------------------------------------------------------------------------------------------------------------------

内存最开始0号地址是BIOS程序用来实现各种功能的地方,不能随便用。内存0xf0000号地址附件还存放着BIOS程序本身,也不能使用。还有其它地方也不能用,

0x00007c00-0x00007dff : 启动区内容的装载地址(这是从7c00到7dff的意思,7c00 + 01ff(511)就是7dff , 一共是512字节

程序中ORG指令的值就是这个数。所以程序才能正常运行。(这个数就是规定)

-----------

projects/02_day/helloos4 下的文件说明:

  • !cons_*.bat 打开命令行窗口的批处理
  • asm.bat 汇编编译批处理,调用了 ..\z_tools\nask.exe
  • helloos.img 最后生成的磁盘镜像文件
  • ipl.bin 汇编编译器..\z_tools\nask.exe 生成的二进制文件
  • ipl.lst 汇编编译生成的输出列表文件,是个文本文件,可以简单的确认每个指令是怎么翻译成机器语言的。
  • ipl.nas 启动程序的汇编源代码
  • install.bat 将镜像写入软盘,没有软驱,现在用不上
  • makeimg.bat 利用 ..\z_tools\edimg.exe ,将bin文件写入并生成镜像文件helloos.img
  • run.bat 将镜像复制到模拟器qemu的文件夹,然后打开模拟器

执行步骤: !con* ->asm ->makeimg -> run 

-------------------------------------------------------------------------------------------------

Makefile工具

利用z_tools/make.exe ,位于tolset/z_new_w文件夹中,调用它的批处理文件 make.bat:

..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9

执行make.exe时,会在执行命令时的当前文件夹下找Makefile这个文件,按钮其内容执行,其内容如下:

#默认操作
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工具来编译,生成IMG镜,运行

make asm 编译nas文件为bin文件

make img 将bin文件写入Img文件 ,默认动作,执行make即 make img

make run 在模拟器上运行img文件

make clear 删除最终结果外的一切中间文件: ipl.bin和ipl.lst

make src_only 删除源代码外的所有: ipl.bin和ipl.lst 和 helloos.img

以上内容放在projects/02_day/helloos5/

posted @ 2020-02-16 15:04  johnjackson  阅读(350)  评论(0编辑  收藏  举报