zoukankan      html  css  js  c++  java
  • 自制操作系统笔记-第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 ask.exe
    • helloos.img 最后生成的磁盘镜像文件
    • ipl.bin 汇编编译器..z_tools ask.exe 生成的二进制文件
    • ipl.lst 汇编编译生成的输出列表文件,是个文本文件,可以简单的确认每个指令是怎么翻译成机器语言的。
    • ipl.nas 启动程序的汇编源代码
    • install.bat 将镜像写入软盘,没有软驱,现在用不上
    • makeimg.bat 利用 ..z_toolsedimg.exe ,将bin文件写入并生成镜像文件helloos.img
    • run.bat 将镜像复制到模拟器qemu的文件夹,然后打开模拟器

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

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

    Makefile工具

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

    ..z_toolsmake.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_toolsqemufdimage0.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/

    喜欢的话,请点赞,转发、收藏、评论,谢谢!
  • 相关阅读:
    Android Studio Gradle 添加.so 支持文件
    poj 3270 更换使用
    linux通过使用mail发送电子邮件
    php 上传文件 $_FILES['']['type']的值
    浅谈Base64编码
    expect实现ssh自动登录
    C++ 多源码文件简单组织
    linux下修改hostid
    SQLite/嵌入式数据库
    类内数组声明,“类外”指定大小
  • 原文地址:https://www.cnblogs.com/johnjackson/p/12297439.html
Copyright © 2011-2022 走看看