网站建设语录,企业网站的内容,外贸营销网站怎么建站,如何做软件app每天进步一点点#xff0c;加油#xff01;
上一节#xff0c;我们通过汇编指令#xff0c;借助操作系统的系统调用实现了向标准输出打印Hello world。这一节我们打算绕过操作系统#xff0c;直接在显示屏幕上打印Hello world。
计算机的启动过程
当我们给计算机加电启…每天进步一点点加油
上一节我们通过汇编指令借助操作系统的系统调用实现了向标准输出打印Hello world。这一节我们打算绕过操作系统直接在显示屏幕上打印Hello world。
计算机的启动过程
当我们给计算机加电启动的时候它的CPU芯片引脚会自动将它的CS和IP寄存器设置成固定的值。比如8086处理器加电的时候CS会被设置为0xFFFFIP会被设置为0x0000。
CS寄存器是代码段寄存器IP是指针寄存器指向CPU将要执行的下一条指令的内存地址真正要执行的指令的物理内存地址由CS寄存器的值左移4位十六进制的一个0加上IP寄存器中的值得到。当时8086这么设计是为了在16位寄存器的CPU上实现20位地址空间的内存寻址即1MB。
后续的80286、80386等为了兼容8086在8086上可以运行的程序到升级后的CPU上仍然可以执行都是遵从这个约定然后会从实模式切换到保护模式实模式下程序中的内存地址就是物理内存地址保护模式下的程序中的内存地址是逻辑地址和物理内存地址有映射关系但那已经是运行时决定的。
计算机加电完的时候CS:IP寄存器指向的指令所在的物理内存地址会是BIOS中固化的程序。BIOS即基本输入输出系统的意思所谓的基本是指它能做的事情很有限毕竟BIOS程序很小它通常用于将操作系统的前面部分装载进内存中操作系统后边的部分由操作系统自己装载。
现在的操作系统基本上都保存在硬盘磁盘中BIOS会从磁盘的0面0道1扇区将其中的指令读取到内存中执行。这个扇区也叫主引导扇区。
如果我们在主引导扇区中写入我们的可执行程序比如汇编文件经过汇编器编译后得到的二进制文件那么就可以让CPU直接执行我们的二进制程序而不用经过操作系统了这正是我们向屏幕打印Hello, world的好时机啊。
使用VirtualBox虚拟机
前面说过我们可以将自己的二进制可执行程序写到硬盘的主引导扇区中让BIOS将我们的程序拷贝到内存中进行执行。 我们打算在虚拟机中模拟这一流程。 我们在虚拟机中可以创建虚拟硬盘它其实是我们宿主机器上的文件比如VHD格式的虚拟硬盘文件。这样我们在宿主机上向这个文件中写入数据然后让虚拟机将它作为磁盘使用这样不就可以在虚拟机刚启动的时候用它的CPU执行我们的二进制可执行文件了么
创建VHD格式虚拟硬盘文件
在管理-工具中创建虚拟硬盘选择VHD格式 下一步选择预分配大小而不是在不够用的时候动态增加的 设置好路径和大小 然后Finish完成。
Hello world汇编文件
hello.asm源码代码稍后会解释
mov ax,0xb800
mov ds,ax
mov byte [0x00],H
mov byte [0x01],0x74
mov byte [0x02],e
mov byte [0x03],0x74
mov byte [0x04],l
mov byte [0x05],0x74
mov byte [0x06],l
mov byte [0x07],0x74
mov byte [0x08],o
mov byte [0x09],0x74
mov byte [0x0a],,
mov byte [0x0b],0x74
mov byte [0x0c],
mov byte [0x0d],0x74
mov byte [0x0e],w
mov byte [0x0f],0x74
mov byte [0x10],o
mov byte [0x11],0x74
mov byte [0x12],r
mov byte [0x13],0x74
mov byte [0x14],l
mov byte [0x15],0x74
mov byte [0x16],d
mov byte [0x17],0x74jmp $
times 510-($-$$) db 0
db 0x55,0xaa通过nasm -f bin hello.asm -o hello.bin将文件汇编成二进制文件。 通过dd ifhello.bin ofhello.vhd bs512 count1 convnotrunc命令将可执行文件复制到刚才创建的VHD文件中bs表示bytes即字节数count1表示之拷贝1个block notrunc表示do not truncate the output file。 dd命令的参数含义可以通过man dd查看:
刚才两个步骤的执行结果如下
启动虚拟机输出Hello world
控制新建虚拟机选择Hard Disk为我们刚才创建的VHD文件 给虚拟机起个名字不用管虚拟机的类型和版本因为我们不是通过ISO文件启动的 启动虚拟机 虚拟机的开机界面上打印出了红色的Hello, world
汇编程序的解释
我们已经实现了绕过操作系统向显示器屏幕上打印Hello world那么hello.asm中的代码分别是什么意思啊 mov ax,0xb800表示将ax寄存器设置为0xb800mov ds,ax表示将ax寄存器中的内容也就是0xb800移动到ds寄存器数据段寄存器中注意汇编语言不支持将立即数直接mov到段寄存器中必须经过通用寄存器如ax的转移。 之所以这么设置是因为8086启动的时候会将内存地址空间中的0xb8000到0xbffff的空间留给显卡的显存。 注意CPU能够访问的内存地址空间中可不完全都是我们说的内存条还有显卡的显存也在内存地址空间中。 等等我们将0xb800赋值给ds但是我们说的显存空间是从0xb8000开始的我们是少赋值了一个0么并不是因为我们汇编代码中后边的mov都是基于ds的比如mov [0x00],H其实相当于mov [ds:0x00],H,ds左移4bit也就是十六进制的一个0之后再加上偏移量才是真正的内存地址。 mov [偏移量],0x74表示的字符的显示颜色是白底红字。这样字符占用1个字节颜色占用1个字节共2个字节用于表示一个字符。 然后我们就将Hello, world这个字符串中的每个字符都mov到0xb8000开始的内存空间上。
在汇编中$表示当前行的内存地址$$表示文件中的第一行的内存地址。 jmp $表示跳转到这个内存地址该行编译后的内存地址取指令执行而它的指令又是跳转到这个地址所以无限循环下去了。因为我们之作了打印Hello, world这一件事不需要CPU做别的事情了就让它陷入死循环了。 times 510-($-$$) db 0的意思是将该行内存地址填充0填充510-前面有内容字节数次。 db 0x55,0xaa的意思是可执行文件的最后两个字节是0x55,0xaa这是主引导扇区512字节的要求最后2个字节必须是这两个否则就认为主引导扇区有问题。
这样我们的汇编程序就是要求CPU在显存开始的地址中拷贝Hello, world字符串然后陷入死循环。程序后边填充0和追加那两个特殊字符只是为了让二进制可执行文件能够被认为是合法的主引导扇区文件大小是512字节后两个字节是符合规定的。 参考资料 1.《x86汇编语言 从实模式到保护模式》第2版