【OS学习笔记】八 实模式:编写主引导扇区代码-另一种更高效的写法

学习交流加

  • 个人qq:
    1126137994
  • 个人微信:
    liu1126137994
  • 学习交流资源分享qq群:
    962535112

上一篇文章,我们用比较原始的方法编写了主引导扇区的代码。点击链接查看上一篇文章:编写主引导扇区代码

本片文章将学习以下内容:

  • 用一种不同的分段方法,从另一个不同的的角度理解处理器的分段内存访问机制
  • 使用循环和条件转移指令来优化上一篇文章的主引导扇区代码

1、代码清单

首先先贴上代码。50行代码,不长。看到汇编不要害怕!!!后面会一步一步分析这个汇编代码的每一条指令的意思。

		 ;代码清单6-1
         ;文件名:c06_mbr.asm
         ;文件说明:硬盘主引导扇区代码
         ; 
      
         jmp near start
         
  mytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,\
            'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07
  number db 0,0,0,0,0
  
  start:
         mov ax,0x07c0  ;设置数据段基地址 
         mov ds,ax
         
         mov ax,0xb800     ;设置附加段基地址,也就是将ES寄存器指向显存的起始地址 
         mov es,ax
         
         cld                   ;方向清零标志,将DF标志位清零,代表传送是正向的
         mov si,mytext        ;SI与DS组成数据段的地址 DS:SI 代表数据的真实物理地址                
         mov di,0             ;DI与ES组成显存的物理地址 ES:DI 代表显存的真实物理地址
         mov cx,(number-mytext)/2   ;实际上等于 13
         rep movsw            ;循环movsw,直到cx寄存器内容为0(rep指令代表反复传送)
     
         ;得到标号所代表的偏移地址
         mov ax,number
         
         ;计算各个数位
         mov bx,ax
         mov cx,5               ;循环次数 
         mov si,10              ;除数 
  digit: 
         xor dx,dx
         div si
         mov [bx],dl            ;保存数位
         inc bx 				  ;使bx寄存器里的值加1
         loop digit
         
         ;显示各个数位
         mov bx,number 		 ;将number的汇编地址传送给BX寄存器
         mov si,4              ;bx+si 得到字符串的每一个字符,SI从4递减到0,这是由于要先显示万位上的数字
   show:
         mov al,[bx+si]
         add al,0x30			;得到它对应的ASCII码
         mov ah,0x04		    ;对应的颜色属性
         mov [es:di],ax		;AX中是一个完整的字,前8位是显示属性值,后8位是字符的ASCII码
         add di,2	  ;DI寄存器在之前用过,现在在“Label offset:” 字符串后面,刚好我们想让number的汇编地址在这里显示
         dec si	      ;SI-1,从number代表的汇编地址的万位到个位,dec指令会影响SF标志位,当SI寄存器的值为0的时候,SF的标志位置1
         jns show	 ;判断SF标志位是否为0,当SF标志位不为0,继续执行show处的代码。当SF标志位为0,则跳过这条指令执行下一条指令。
         
         mov word [es:di],0x0744	;高字节0x07是黑底白字的属性,低字节0x44是字符‘D’的ASCII码

         jmp near $   				;相当于 infi: jmp near infi

  times 510-($-$$) db 0           ; 计算512字节中,需要填满的字节有哪些。
                   db 0x55,0xaa   ;一个有效的主引导扇区,最后两字节必须是0x55 0xaa

2、代码分析

坚持看完,一定能看懂!!!

  • 8行-9行:这里声明了非指令的数据。一般来说,所有处理器指令都是按顺序存放,在他们中间不允许夹杂非指令的数据。但是如果有办法让处理器不执行这些数据,则又另当别论。如第6行的代码。

这两行声明的是要在显示屏上显示的数据:"Label offset: ",其中0x07是每个字符的显示属性值。

  • 6行:它是一条转移指令。让处理器跳转到标号start处开始执行。这就避开了数据区。
  • 13-14行:设置数据段的基地址。DS代表数据段的基地址。

这里为什么是0x07c0呢?

由上几篇文章学过的知识知道,主引导扇区程序加载时,被加载到的位置是0x0000:0x7c00.也就是物理地址:0x07c00 这其实就是将整个物理地址空间看成是基地址0x0000,偏移地址0x7c00的分段方式。

这样的话,CPU每次访问内存的时候总是要加上0x7c00这个偏移地址。但是程序中一般访问内存的指令非常多,每一条都加上0x7c00很不现实。

但是Intel处理器的分段策略很灵活。逻辑地址0x0000:0x7c00对应的物理地址是0x07c00 ,而该地址又是另一个逻辑地址0x07c0:0x0000的地址。如下图是以两个逻辑段的视角看待同一个内存区域。

我们可以将512字节的区域看成是一个单独的段。段的基地址是:0x07c0 段长512字节。注意,该段的最大长度是64KB,但是这里我们实际上只用了512字节。尽管BIOS是将主引导扇区加载到物理地址0x07c00处,但是我们却可以认为它是从0x07c0:0x0000处开始加载的。

所以13-14行将数据段寄存器DS指向0x07c0

  • 16-17行:使附加段寄存器ES的内容指向显存的基地址0xb800
  • 19-23行:循环movsw,直到cx寄存器内容为0(rep指令代表反复传送)。这里是循环将DS:SI所指向的数据传送到ES:DI所指定的显示缓冲区。

循环movsw与movsb指令执行时,将DS:SI所指向的数据传送到ES:DI所指定地址。同时每传送一次 ,CX寄存器的内容减一。

rep代表循环movsw,直到寄存CX的内容为0为止。所以22行中,计算出数据的字节数,并将其传送到CX寄存器。

20行将SI指向数据区的首地址,SI与DS组成数据段的地址 DS:SI 代表数据的真实物理地址

21行将0给DI寄存器,DI与ES组成显存的物理地址 ES:DI 代表显存的真实物理地址。很明显,我们是从显存的0偏移地址开始存数据。

19行,方向清零标志,将DF标志位清零,代表传送是正向的。**正向的意思是传送操作的方向是从内存的低地址端到搞地质端。**很明显我们是正向传送。

  • 26行:我们还是想像上一篇文章一样,显示字符串后将number这个标号的数值显示出来。所以先将number标号的汇编地址传送给AX寄存器保存。后面会用。

  • 29-37行:还记得上一篇文章是如何分解number的各个数位的么?如果不记得,请点击链接查看:上一篇文章 上一篇文章是一个一个分解然后保存的。这里有所改变。使用了循环,可以让我们少写很多代码。这里就不多说了,不懂的看上一篇文章,这个循环也很好理解,loop这个指令将循环次数CX减一,指导CX等于0为止。

  • 40-49行:显示标号number的汇编地址的各个数位。同理,如何显示各个数位,可以查看上一篇文章。这里只是将重复的代码,写成了循环的形式。

jns这个指令判断SF标志位是否为0,当SF标志位不为0,继续执行show处的代码。当SF标志位为0,则跳过这条指令执行下一条指令。

dec指令会影响SF标志位,当SI寄存器的值为0的时候,SF的标志位置1

这里唯一需要注意的是低端字节序传送的时候,寄存器的低字节传送到显示缓冲区的低地址部分,寄存器的高字节传送到显示缓冲区的高地址部分。如下图所示:

  • 51行:显示字符‘D’
  • 53行:死循环
  • 55行:计算512字节中,空字节有多少,然后将这些空字节填满0

$ 代表当前行的汇编地址
$$ 代表当前段的起始地址。由于本程序没有定义段,所以自成一个段,并且起始地址是0地址。

  • 56行:一个有效的主引导扇区,最后两字节必须是0x55 0xaa

3、编译运行

将我们汇编代码编译好的二进制bin文件写到虚拟硬盘的主引导扇区中。启动虚拟机,就会运行我们写的代码,运行结果如下:

今天的程序运行的很顺利。

4、总结

了解汇编的运行机制,对以后深入学习高级语言,很有帮助:比如JVM。

笔记记得不是很全,像汇编的语法以及如何将代码写到虚拟硬盘的主引导扇区这些都没有写。如果又不懂的可以加我联系方式一起交流。

学习探讨加个人:
qq:1126137994
微信:liu1126137994

全部评论

相关推荐

避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
点赞 评论 收藏
分享
长鑫存储
投递长鑫存储等公司6个岗位 >
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务