本章目标:
- 模拟操作系统加载应用程序的过程,演示段的重定位方法,彻底理解8086处理器的分段内存管理机制
- 学习x86处理器过程调用的程序执行机制
- 了解x86处理器访问外围硬件设备的方法
- 总结JMP和CALL指令的全部格式
- 认识更多的x86处理器指令,如in,out,shl,shr,rol,ror,jmp,call,ret等
8.1本章代码清单
8-1,主引导扇区程序加载器
8-2,被加载的应用程序
8.2 用户程序的结构
8.2.1 分段、段的汇编地址和段内汇编地址
1.SECTION、SEGMENT段
- NASM汇编指令通过“SECTION”或者“SEGMENT”来定义段,一旦定义段,后面的内容就都属于该段,除非出现了另一个段的定义
SECTION 段名称
或者
SEGMENT 段名称
-
“align=”子句
用于指定某个SECTION的汇编对齐方式
align=16",表示段是16字节对齐,即该物理地址能被16整除 -
"section.段名称.start"子句
段header相对于整个程序开头的汇编地址是section.header.start -
"vstart"子句
尽管定义了段,但是引用某个标号时,该标号处的汇编地址依然是从整个程序的开头开始算起的,而不是从段开头开始计算
8.2.2 用户程序头部
- 加载器和用户程序是不同的个体开发的,因此需要使用“程序头部”来进行协商
- 程序头部组成
1)用户程序的长度,以字节为单位的大小
2)应用程序的入口点,包括段地址和偏移地址。这是因为应用程序不仅仅只有一个代码段
3)段重定位表。存有每个段的段地址,交由加载器进行重定位工作。因为汇编代码的标号是汇编地址,需要通过重定位表来转为内存逻辑地址
8.3 加载程序(器)的工作流程
8.3.1 初始化和决定加载位置
加载器需要决定两件事
- 看看内存中的什么地方是空闲的,即从哪个物理内存开始加载用户程序
- 用户程序位于硬盘的什么位置,它的起始逻辑扇区号是什么
- 起初,我们直接定义一个可用的物理内存地址0x10000,内存空间规划如下
1、equ伪指令
equ伪指令用来声明常数,它的意思是“等于”。
和db,dw,dd不同,用equ声明的数值不占用任何汇编地址,也不在运行时占用任何内存位置。
8.3.2 准备加载用户程序
解读8-1代码的12到21行
8.3.3 外围设备及其接口
处理器和外围设备通信需要解决两个问题
- 不可能所有的I/O接口都和处理器相连 ------ 总线
- 各个I/O接口之间的冲突如何解决 ----- 使用输入输出控制设备集中器芯片(I/O Controller Hub,ICH),在个人计算机上,就是所谓的南桥
8.3.4 I/O端口和端口访问
- 处理器是通过端口(PORT)来和外围设备打交道的。本质上,端口就是一些寄存器,类似于处理器内部的寄存器,不同之处在于端口寄存器位于I/O接口电路中。
例如:
连接硬盘的PATA/SATA接口有几个端口
命令端口:当向该端口写入0x20时,表明是从硬盘读数据;写入0x30时,表明是向硬盘写数据。
状态端口:处理器根据这个端口的数据来判断硬盘工作是否正常,操作是否成功,发生了哪种错误
参数端口:处理器通过这些端