intelx86为何从0xFFFF0处执行
第一条指令的地址
在用户按下计算机电源开关之后,CPU会自动的将其CS寄存器设定为0xFFFF,将其IP寄存器设定为0x0000。由于CS:IP指出了下一条指令的地址[1],因此CPU会跳到0xFFFF:0x0000处进行执行。为什么是这个地址而不是其它地址呢?这其实是一个很巧妙的设计。
我们知道,从80386开始,到后面80486、奔腾,它们都是32位的CPU,但是它们都与Intel先前开发的8086兼容。也就是说,在默认情况下,80386、80486等,只不过是一台运行得更快一些的8086罢了。因此,这里我们只讨论8086[2]。
8086是16位的CPU,但是却有20根地址线[3]。也就是说它可以寻址 220 = 1M 内存空间。这段内存空间由RAM、ROM组成。ROM是随机只读存储器,里面的程序是在计算机出厂的时候直接烧录在里面的,完成一些主机自检等操作,并提 供一些访问磁盘等基本输入输出服务,因而这段程序常被称为BIOS(Basic Input/Ouput Service)。由于不同的计算机厂商生产的计算机所带的外设不一样,因此,这段程序大小也限机型的不同而不一样,有可能A厂出产的计算机所带的这段程 序的大小为1K,而B厂出产的这段程序的大小为2K。如果将这段程序放在0x0000处,那么用户写的程序就可能从0x0400处开始也可能从 0x0800处开始,非常不统一。故而,将此段程序放在1M内存的顶部,那么用户写的程序就都可以从0x0000处开始了。
但将BIOS这段程序放在1M内存的顶部,如果这段程序大小为1K,那么应当从0xFFC00开始放。如果这段程序的大小为2K,那 么应当从0xFF800开始放,对于CPU而言,到底是应当从0xFFC00开始执行还是应当从0xFF800开始执行呢?为了解决这个问题,8086规 定,CPU均从0xFFFF0处开始执行,而在0xFFFF0处,放一条无条件转移指令JMP。如果A厂的BIOS是从0xFFC00开始放的,那么这条 转移指令就跳转到0xFFC00处开始执行。如果B厂的BIOS是从0xFF800开始放的,那么这条转移指令就跳转到0xFF800处开始执行,各个厂 家可以跟据自己所生产的BIOS程序的大小,来决定此转移指令具体跳转到的位置。
这里有一点需要清楚的是,通常认为,内存编址是连续的,不会出现空洞,其实完全不是这样。比如,假设BIOS的编址是从 0xF0000开始,而RAM,即通常讲的内存编址是从0x00000开始,那么,如果用户只安装了32K内存,那么内存的编址范围就是 0x00000~0x07FFF,那么从0x08000至0xEFFFF处就没有安装内存,这就是一个内存空洞。
好了,当CPU执行了放在0xFFFF0处的第一条指令后,就跳转到BIOS程序内部去执行了,下面就来看看BIOS都做了些什么。
BIOS的工作
BIOS的工作相当简单,主要的工作就是执行主机自检(POST),然后查找操作系统存在在哪个磁盘上,将操作系统载入。BIOS在查找各磁盘 的操作系统时,主要是查找磁盘上的第一个扇区(0面0磁道1扇区),每个扇区是512字节,如果这是一个引导扇区,那么就将它载入0x7C00的内存地址上,然后跳转到此地址上执行。如果此不是一个引导扇区,就继续查找下一个磁盘,看其上面是否存在引导扇区。如果所有的磁盘上都不存在引导扇区,则在屏幕上 打印出一条出错信息。
引导扇区的工作
引导扇区只有一扇区即512字节大,因此它的主要目的是把操作系统的内核读进内存,然后跳转到操作系统内核处开始执行。从编写操作系统角度来 说,前面的CPU上电及BIOS的工作都不是操作系统能控制的,而从引导扇区开始,就完完全全可由操作系统来控制了,因此,编写引导扇区也是编写操作系统 必要的工作之一。从BIOS跳入引导扇区后,计算机系统引导工作就算完成,怎样把操作系统内核读进内存,然后再安排一条跳转指令跳到内核处执行就是操作系 统开发人员的工作了。
intelx86为何从0xFFFF0处执行的更多相关文章
- C语言实现程序跳转到绝对地址0x100000处执行
嵌入式笔试题:想让程序跳转到绝对地址0x100000处执行,该如何做? 请详细解释一下所给的答案: 网上看到有如下答案: *((void(*)(void))0x100000)(); 经过在VC++6. ...
- 【Node.js】Event Loop执行顺序详解
本文基于node 0.10.22版本 关于EventLoop是什么,请看阮老师写的什么是EventLoop 本文讲述的是EventLoop中的执行顺序(着重讲setImmediate, setTime ...
- Java Main如何被执行?(转)
java应用程序的启动在/hotspot/src/share/tools/launcher/java.c的main()函数中,而在虚拟机初始化过程中,将创建并启动Java的Main线程.最后将调用JN ...
- erlang虚拟机代码执行原理
转载:http://blog.csdn.NET/mycwq/article/details/45653897 erlang是开源的,很多人都研究过源代码.但是,从erlang代码到c代码,这是个不小 ...
- mysql 批处理命令执行多个sql脚本
方法1 若有SQL脚本a.sql, b.sql, 其目录在f盘根目录下, 则可再写一个SQL脚本c.sql(假设其目录也在f盘根目录下, 也可以在其他路径下)如下: source f:/a.sql; ...
- Java Main如何被执行?
java应用程序的启动在在/hotspot/src/share/tools/launcher/java.c的main()函数中,而在虚拟机初始化过程中,将创建并启动Java的Main线程.最后将调用J ...
- [WEB安全]无回显代码执行【转载】
原作者:AdminTony 原文链接:http://www.admintony.com/无回显代码执行利用方法.html 在Root-Me上有一道代码执行的题目,其链接为题目链接 0x01 简介 打开 ...
- python函数的执行过程
对于 Python 常规函数,都只有一个入口,但会有多个出口如 return 返回或者抛出异常.函数从入口进入会一直运行到 return 语句或者抛出异常,中间不会暂停,函数一直拥有控制权.当运行结束 ...
- linux 驱动学习笔记03--Linux 内核的引导
如图所示为 X86 PC 上从上电/复位到运行 Linux 用户空间初始进程的流程.在进入与 Linux相关代码之间,会经历如下阶段. ( 1 ) 当系统上电或复位时, CPU 会将 PC 指针赋值为 ...
随机推荐
- day10 Pyhton学习
一.昨日内容回顾 函数: 定义:对功能或者动作的封装 def 函数名(形参): 函数体 函数名(实参) return: 返回,当程序运行到return的时候,终止函数的执行 一个函数一定拥有返回值 ...
- python接口测试之日志功能
之前在简书中看了一篇关于日志功能的文档,供大家参考:https://www.jianshu.com/p/62f7b49b41e7 Python通过logging模块提供日志功能,所以直接导入即可 im ...
- 学习使用C语言/C++编程的7个步骤!超赞~
C是一种编译性语言.如果你以前从来没有接触过任何的编程语言,那么你则需要学习一下一个拆分的逻辑思维.当我们想要写一个项目或者软件的时候,我们需要把这个整体拆分为7个步骤,这样也会让你的思路看起来更有条 ...
- C语言-入门级编程语言--编程小白首选
我们都知道计算机很厉害,利用计算机可以高效地处理和加工信息,随着计算机技术的发展,计算机的功能越来越强大,不但能够处理数值信息,而且还能处理各种文字.图形.图像.动画.声音等非数值信息. 在199 ...
- spring boot:使用mybatis访问多个mysql数据源/查看Hikari连接池的统计信息(spring boot 2.3.1)
一,为什么要访问多个mysql数据源? 实际的生产环境中,我们的数据并不会总放在一个数据库, 例如:业务数据库:存放了用户/商品/订单 统计数据库:按年.月.日的针对用户.商品.订单的统计表 因为统计 ...
- linux 压缩命令 zip
1.zip命令 例如:zip -r mysql.zip mysql 该句命令的含义是:将mysql文件夹压缩成mysql.zip zip -r abcdef.zip abc def.txt 这句命令的 ...
- .Net Core单元测试规范
.Net Core单元测试规范 一. 前言 为了有效提升代码质量,保证DevOps的顺利进行.将全面开始采用单元测试进行覆盖,届时单元测试将完全纳入 到完整的持续构建生命周期中做为第一道质量把控的门槛 ...
- 浏览器页面左上角出现undefined
浏览器页面左上角出现undefined, js文档中: let list; list += html代码; 解决办法: let list = html代码;
- c++ qsort的使用
c++ qsort的使用 qsort函数定义在头文件algorithm中,使用时需要include该头文件 void qsort (void* base, size_t num, size_t siz ...
- 在java的多态调用中,new的是哪一个类就是调用的哪个类的方法。
在java的多态调用中,new的是哪一个类就是调用的哪个类的方法.(x) 原因: ava多态有两种情况:重载和覆写 在覆写中,运用的是动态单分配,是根据new的类型确定对象,从而确定调用的方法: 在重 ...