上一篇x86汇编从实模式到保护模式-带你轻松入门编程-彻底理解程序的本质01
在上一篇,我们写了下面2条汇编指令
mov ax ,1
add ax , 2
由于汇编指令,CPU无法执行,所以我们用汇编编译器将汇编指令转化成了CPU指令.
打开test.bin
CPU指令在test.bin文件里。我们可以打开test.bin,看下里面的内容。
如果你用普通的软件打开test.bin,你会看到如下的内容
显示的是一串乱码,想要正确的打开这个文件,需要通过特殊的软件查看器。我这里提供了一个
没有的朋友,可以去如下下载
链接:https://pan.baidu.com/s/1zB9r5WwuTMIPNMlYl5HlvA
提取码:5ndl
用HexView.exe打开test.bin
现在我就用HexView.exe打开test.bin,内容如下
可以发现
mov ax , 1 转化成了B8 01 00
add ax , 2 转化成了83 C0 02
如何让CPU执行我们刚刚编译的汇编指令
现在我们遇到了一个很麻烦的问题,就是如何让CPU去执行test.bin中的cpu指令。现在test.bin是保存在硬盘里的,而我们无法让CPU直接跳转到硬盘里去执行test.bin,为什么无法跳转?因为CPU的设计者,没有设计这个跳转电路。所幸的是CPU会从内存里获取cpu指令,然后在cpu内部自动开始执行。
因此解决问题的办法就是想办法将硬盘里的test.bin加载到内存里,然后告诉cpu test.bin在内存中的位置。
如何将硬盘里的test.bin加载到内存里
现在又有新问题了,我们应该如何将test.bin加载到内存里呢?先来看下如下的图
大家初次看到上面的流程图,有没有被吓到,别担心,我们来逐步分析。
先来看第一个步骤,我们打开电脑的电源,此时CPU开始工作了,CPU首先会去BIOS中读取CPU指令。这里BIOS实际上是主板上的一块芯片名称,它有自己的存储器,这个存储器在生产的时候,就预先往里面保存了很多的CPU指令。
这些CPU指令有2大作用。
第一:检测硬件是否有损坏,比如说,这些指令会检测内存条有没有坏掉,如果坏掉了,CPU就会停止工作。
第二:如果硬件检测通过,那么它就会将硬盘的第0扇区的内容复制到内存的0x7c00处。
0扇区的内容保存到内存的0x7c00后,BIOS程序,就会通知CPU到0x7c00这个位置去获取cpu指令,cpu获取到指令后,就会自动开始执行。
由以上的步骤,我们可以知道,只要我们将test.bin放到硬盘的第0扇区,然后启动电脑,BIOS会将test.bin放到内存的0x7c00,然后CPU就会去0x7c00获取指令,然后在cpu内部开始执行。
虽然我们已经知道要将test.bin放到硬盘的第0扇区,但现实却不允许我们这样做。因为现在你的windows操作系统的引导程序就是放在硬盘的第0扇区,如果你此时将test.bin放到0扇区,那就会覆盖掉操作系统的引导程序,到时你就再也无法启动windows了。
使用虚拟机来完成测试
那么此时又要咋搞呢?有一种解决办法就是,我们使用虚拟机。
虚拟机是一种很强大的软件,它可以用软件模拟一个CPU,内存,硬盘等硬件。可以这样说,真实计算机有的,虚拟机都可以模拟出来。大家可以看如下文章,将虚拟机和虚拟硬盘配置起来。
将test.bin的内容复制到虚拟硬盘的0扇区
打开,没有这个软件的朋友,到如下下载
链接:https://pan.baidu.com/s/1zB9r5WwuTMIPNMlYl5HlvA
提取码:5ndl
点击选择虚拟硬盘文件
点击打开
点击下一步
点击选择,这里实际上就是选择test.bin
输入0,就代表0扇区
点击写入文件
启动虚拟机
OK,到此为止。花费了很多的功夫,现在虚拟机有了,虚拟硬盘的0扇区也写入了我们的cpu指令。按照我们之前的想法,现在只需要启动虚拟机,虚拟机中的cpu,就会到虚拟机的内存的0x7c00处加载指令,然后在虚拟机的CPU内部开始执行。
那么现在就启动虚拟机吧
点击启动
运行结果如下
当我们满心欢喜的启动虚拟机后,竟然弹出这么个玩意,很明显CPU并没有找到我们硬盘0扇区的test.bin,你是不是很困惑,刚刚我们明明已经将test.bin中的内容写入到0扇区了,为什么会找不到呢?
原因是这样,BIOS在读取0扇区的内容后,会检测0扇区的最后2个字节是不是以0x55和0xAA结尾,如果没有,BIOS就会认为0扇区的内容是无效的,于是它就拒绝让CPU去执行这部分代码。而我们的代码里,很明显没有以0x55 和0xAA结尾。所以导致test.bin被拒绝执行了。
在主扇区的末尾添加0x55和0xAA
既然知道了原因,那我们添加0x55和0xAA就是了。在test.asm中,改造如下
mov ax,1
add ax,2
hlt
times 510-($-$$) db 0
db 0x55,0xaa
hlt执行后,CPU就会暂停工作,我希望CPU执行完mov ax,1和add ax,2之后,就先暂停
硬盘的每一个扇区是512字节,为了让0x55和0xaa恰好位于最后2字节。我用times 重复存储了510-($-$$)个0,注意这里的0没有任何意义,纯粹用于占位。
$代表当前行的偏移
$$代表开始处的偏移。
$-$$就表示当前使用了多少个字节的空间
510 减去已经使用的字节空间就等于,还需要填充多少数据,才能到510字节。在510字节之后,再保存0x55和0xaa,就刚好是512字节了。
此时我们重新编译汇编指令,然后编译后的test.bin继续写入到虚拟硬盘的0扇区,此时再次启动虚拟机,效果如下
如果你发现窗口里,只有1个光标在闪烁的时候,就说明我们的指令被执行了。由于执行的结果,并没有输出到屏幕上。我们看不到任何的现象。实际计算的结果是保存在寄存器的ax里,并且结果是3.