万州做网站的公司,wordpress练习,九江市建设工程门户网站,海拉尔网站开发学习交流加 个人qq#xff1a; 1126137994个人微信#xff1a; liu1126137994学习交流资源分享qq群#xff1a; 962535112 上一篇文章#xff0c;我们用比较原始的方法编写了主引导扇区的代码。点击链接查看上一篇文章#xff1a;编写主引导扇区代码
本片文章将学习以下内… 学习交流加 个人qq 1126137994个人微信 liu1126137994学习交流资源分享qq群 962535112 上一篇文章我们用比较原始的方法编写了主引导扇区的代码。点击链接查看上一篇文章编写主引导扇区代码
本片文章将学习以下内容
用一种不同的分段方法从另一个不同的的角度理解处理器的分段内存访问机制使用循环和条件转移指令来优化上一篇文章的主引导扇区代码 文章目录1、代码清单2、代码分析3、编译运行4、总结1、代码清单
首先先贴上代码。50行代码不长。看到汇编不要害怕后面会一步一步分析这个汇编代码的每一条指令的意思。 ;代码清单6-1;文件名c06_mbr.asm;文件说明硬盘主引导扇区代码; jmp near startmytext db L,0x07,a,0x07,b,0x07,e,0x07,l,0x07, ,0x07,o,0x07,\f,0x07,f,0x07,s,0x07,e,0x07,t,0x07,:,0x07number db 0,0,0,0,0start:mov ax,0x07c0 ;设置数据段基地址 mov ds,axmov ax,0xb800 ;设置附加段基地址也就是将ES寄存器指向显存的起始地址 mov es,axcld ;方向清零标志将DF标志位清零代表传送是正向的mov si,mytext ;SI与DS组成数据段的地址 DS:SI 代表数据的真实物理地址 mov di,0 ;DI与ES组成显存的物理地址 ES:DI 代表显存的真实物理地址mov cx,(number-mytext)/2 ;实际上等于 13rep movsw ;循环movsw直到cx寄存器内容为0rep指令代表反复传送;得到标号所代表的偏移地址mov ax,number;计算各个数位mov bx,axmov cx,5 ;循环次数 mov si,10 ;除数 digit: xor dx,dxdiv simov [bx],dl ;保存数位inc bx ;使bx寄存器里的值加1loop digit;显示各个数位mov bx,number ;将number的汇编地址传送给BX寄存器mov si,4 ;bxsi 得到字符串的每一个字符SI从4递减到0这是由于要先显示万位上的数字show:mov al,[bxsi]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的标志位置1jns show ;判断SF标志位是否为0当SF标志位不为0继续执行show处的代码。当SF标志位为0则跳过这条指令执行下一条指令。mov word [es:di],0x0744 ;高字节0x07是黑底白字的属性低字节0x44是字符‘D’的ASCII码jmp near $ ;相当于 infi: jmp near infitimes 510-($-$$) db 0 ; 计算512字节中需要填满的字节有哪些。db 0x55,0xaa ;一个有效的主引导扇区最后两字节必须是0x55 0xaa2、代码分析
坚持看完一定能看懂
8行-9行这里声明了非指令的数据。一般来说所有处理器指令都是按顺序存放在他们中间不允许夹杂非指令的数据。但是如果有办法让处理器不执行这些数据则又另当别论。如第6行的代码。
这两行声明的是要在显示屏上显示的数据Label offset: ,其中0x07是每个字符的显示属性值。
6行它是一条转移指令。让处理器跳转到标号start处开始执行。这就避开了数据区。13-14行设置数据段的基地址。DS代表数据段的基地址。
这里为什么是0x07c0呢
由上几篇文章学过的知识知道主引导扇区程序加载时被加载到的位置是0x0000:0x7c00.也就是物理地址0x07c00 这其实就是将整个物理地址空间看成是基地址0x0000偏移地址0x7c00的分段方式。
这样的话CPU每次访问内存的时候总是要加上0x7c00这个偏移地址。但是程序中一般访问内存的指令非常多每一条都加上0x7c00很不现实。
但是Intel处理器的分段策略很灵活。逻辑地址0x0000:0x7c00对应的物理地址是0x07c00 而该地址又是另一个逻辑地址0x07c00x0000的地址。如下图是以两个逻辑段的视角看待同一个内存区域。 我们可以将512字节的区域看成是一个单独的段。段的基地址是0x07c0 段长512字节。注意该段的最大长度是64KB但是这里我们实际上只用了512字节。尽管BIOS是将主引导扇区加载到物理地址0x07c00处但是我们却可以认为它是从0x07c00x0000处开始加载的。
所以13-14行将数据段寄存器DS指向0x07c0
16-17行使附加段寄存器ES的内容指向显存的基地址0xb80019-23行循环movsw直到cx寄存器内容为0rep指令代表反复传送。这里是循环将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。
笔记记得不是很全像汇编的语法以及如何将代码写到虚拟硬盘的主引导扇区这些都没有写。如果又不懂的可以加我联系方式一起交流。
学习探讨加个人 qq1126137994 微信liu1126137994