16位MS - DOS编程及相关技术详解
1 16位MS - DOS编程基础
1.1 MS - DOS与IBM - PC
- 内存地址:最高地址为9FFFFh。
- 中断向量表:在系统中起着重要作用。
- 特定地址:00400h有特定用途。
- 基础服务:BIOS提供基本的输入输出服务。
-
输出重定向:若程序名为myProg.exe,使用
myProg > prn可将其输出重定向到默认打印机。 - 打印设备:默认打印机为LPT1。
- 中断服务例程:为应用程序提供基本服务并处理硬件事件。
- 中断处理:进入中断时需将标志压入栈。
- 中断处理步骤:可参考特定章节的四个步骤。
- 中断返回:中断处理程序通过执行IRET指令返回。
- 中断号对应地址:如21h中断号对应的地址为0084h(21h * 4)。
1.2 MS - DOS功能调用(INT 21h)
| 功能 | 说明 |
|---|---|
| AH寄存器 | 用于指定功能号 |
| 功能4Ch | 用于程序终止 |
| 功能2和6 | 用于写入单个字符 |
| 功能9 | 用于显示字符串 |
| 功能40h | 用于文件写入 |
| 功能1和6 | 用于字符输入 |
| 功能3Fh | 用于文件读取 |
| 功能2Ah和2Bh | 用于获取和设置日期时间 |
| 功能2Bh和2Dh | 用于设置系统日期和时间 |
| 功能6 | 用于字符输入 |
1.3 标准MS - DOS文件I/O服务
-
设备句柄:
- 0:键盘(标准输入)
- 1:控制台(标准输出)
- 2:错误输出
- 3:辅助设备(异步)
- 4:打印机
- 错误标志:使用进位标志判断操作是否出错。
- 功能716Ch参数:
AX = 716Ch
BX = 访问模式 (0 = 只读, 1 = 只写, 2 = 读写)
CX = 属性 (0 = 正常, 1 = 只读, 2 = 隐藏, 3 = 系统, 8 = 卷标ID, 20h = 存档)
DX = 操作 (1 = 打开, 2 = 截断, 10h = 创建)
DS:SI = 文件名的段/偏移地址
DI = 别名提示 (可选)
- 打开现有文件用于输入的代码示例:
.data
infile BYTE "myfile.txt",0
inHandle WORD ?
.code
mov ax,716Ch ; 扩展创建或打开
mov bx,0 ; 模式 = 只读
mov cx,0 ; 正常属性
mov dx,1 ; 操作: 打开
mov si,OFFSET infile
int 21h ; 调用MS - DOS
jc quit ; 出错则退出
mov inHandle,ax
- 文件读取:使用INT 21h功能3Fh读取二进制数组,参数如下:
AH = 3Fh
BX = 打开的文件句柄
CX = 最大读取字节数
DS:DX = 输入缓冲区地址
- 文件结束判断:调用INT 21h后,比较AX中的返回值和调用前CX中的值,若AX较小则到达文件末尾。
- 键盘与文件读取区别:仅BX的值不同,键盘读取时BX为0,文件读取时BX为打开文件的句柄。
- 文件指针移动:使用功能42h,代码示例如下:
; BX已包含文件句柄
mov ah,42h ; 移动文件指针
mov al,0 ; 方法: 从开头偏移
mov cx,0 ; 偏移高字节
mov dx,50 ; 偏移低字节
int 21h
2 磁盘基础
2.1 磁盘存储系统
- 相关判断:部分描述为真,部分为假。
- 存储结构:涉及柱面、扇区等概念。
- 扇区大小:每个扇区大小为512字节。
- 访问速度:相邻柱面访问速度快,因为读写头移动距离小。
- 磁头移动问题:磁头跨越其他柱面会浪费时间并增加出错概率。
- 存储单元:磁盘以卷为存储单元。
- 寻道时间:指读写头在磁道间移动的平均时间。
- 扇区标记:磁盘表面的物理扇区需要进行标记。
- 主引导记录:包含磁盘分区表和引导程序,用于加载操作系统。
- 分区情况:通常有一个分区。
- 分区类型:存在系统分区。
2.2 文件系统
| 文件系统特性 | 说明 |
|---|---|
| 存储要求 | 所有文件系统至少需要一个簇来存储文件 |
| 最大容量 | FAT32和NTFS支持较大容量,如4GB、8GB等 |
| 系统优势 | NTFS在多方面具有优势 |
| 结构组成 | 包括引导记录、文件分配表、根目录和数据区 |
| 信息位置 | 特定信息位于引导记录的0Dh偏移处 |
| 簇使用情况 | 存储8200字节的文件可能需要两个8KB簇,浪费8184字节 |
2.3 磁盘目录
- 目录判断:部分描述为真,部分为假。
- 目录结构:根目录有特定的结构和名称。
- 目录项大小:每个目录项为32字节。
- 目录项内容:包含文件名、扩展名、属性、时间戳、起始簇号和文件大小等。
- 状态字节:状态字节及其描述可参考特定表格。
- 时间编码:时间信息按位编码,如0 - 4位表示秒,5 - 10位表示分钟,11 - 15位表示小时。
- 长文件名:长文件名有特定的编码方式,如第一个字节为4xh,x表示长文件名项的数量。
- 文件名项:可能需要两个文件名项。
- 新字段:存在最后访问日期、创建日期和创建时间三个新字段。
- 文件分配表链接:用于文件存储的组织。
2.4 读写磁盘扇区
- 功能判断:部分描述为真,部分为假。
- 功能参数:
AX: 7305h
DS:BX: DISKIO结构变量的段/偏移地址
CX: 0FFFFh
DL: 驱动器号 (0 = 默认, 1 = A, 2 = B, 3 = C等)
SI: 读写标志
- 特殊显示:INT 10h可显示特殊ASCII图形字符而不解释为控制码。
- 错误处理:功能7305h读取扇区失败时,进位标志置位并显示错误信息(注意在某些Windows系统下无法测试)。
2.5 系统级文件函数
| 功能 | 说明 |
|---|---|
| 功能7303h | 有特定用途 |
| 功能39h | 用于创建子目录 |
| 功能3Bh | 用于设置当前目录 |
| 功能7143h | 用于获取和设置文件属性 |
3 BIOS级编程
3.1 键盘输入(INT 16h)
- 最佳选择:INT 16h是处理键盘输入的最佳方式。
- 缓冲区位置:键盘预输入缓冲区位于0040:001E。
- 输入处理:INT 9h读取键盘输入端口,获取扫描码并生成ASCII码,存入缓冲区。
-
功能调用:
- 功能05h
- 功能10h
- 功能11h:用于检查缓冲区是否有按键等待
- 功能12h:用于获取键盘标志
- 按键判断:通过位操作判断按键状态,如判断Ctrl键是否按下的代码示例:
L1:
mov ah,12h ; 获取键盘标志
int 16h
test al,100h ; Ctrl键按下?
jz L1 ; 否: 重复循环
; 此时Ctrl键已按下
- 其他按键检查:可通过添加CMP和JE指令检查其他按键,如ESC、F1和Home键:
L1:
; ...
cmp ah,1 ; ESC键的扫描码?
je quit ; 是: 退出
cmp ah,3Bh ; F1功能键?
je quit ; 是: 退出
cmp ah,47h ; Home键?
je quit ; 是: 退出
jmp L1 ; 否: 再次检查缓冲区
3.2 视频编程(INT 10h)
- 编程级别:包括MS - DOS级、BIOS级和直接视频级。
- 显示方式:直接视频方式有其特点。
-
全屏模式切换:在MS - Windows中有两种方式:
- 创建程序EXE文件的快捷方式,打开属性对话框,选择屏幕属性并选择全屏模式。
- 从开始菜单打开命令窗口,按Alt - Enter切换到全屏模式,使用CD命令导航到EXE文件目录并运行程序,再次按Alt - Enter可返回窗口模式。
- 显示模式:常用模式如模式3(彩色,80×25)。
- 显示内容:每个显示单元包含ASCII码和属性(2字节)。
- 颜色组成:颜色由红、绿、蓝和亮度组成。
- 颜色位分配:背景颜色由位4 - 7控制,前景颜色由位0 - 3控制。
-
功能调用:
- 功能02h:用于设置光标位置
- 功能06h:用于滚动屏幕
- 功能09h:用于显示字符
- 功能01h:用于设置光标形状
- 功能00h:用于设置视频模式
- 功能10h子功能03h:用于获取光标位置
- 功能06h且AL为0:用于清屏
- 光标控制:可通过设置光标顶部行为非法值或将光标置于显示范围外隐藏光标。
- 参数设置:不同功能有不同的参数设置,如设置光标位置时AH = 2,DH为行号,DL为列号,BH为视频页。
3.3 图形绘制(INT 10h)
- 绘图功能:使用功能0Ch进行图形绘制。
- 参数设置:
AH = 0Ch
AL = 像素值
BH = 视频页
CX = X坐标
DX = Y坐标
- 性能问题:绘制速度较慢。
- 模式设置:代码示例如下:
mov ah,0 ; 设置视频模式
mov al,11h ; 到模式11h
int 10h ; 调用BIOS
- 特定模式:如模式6Ah。
-
坐标计算:有特定的坐标计算公式,如
sx = (sOrigX + X)。 - 坐标示例:给出了一些坐标示例,如(350,150)、(375,225)、(150,400)。
3.4 内存映射图形
- 像素对应:每个字节对应1个像素。
- 颜色映射:模式13h将像素整数值映射到调色板。
- 颜色索引:像素的颜色索引用于确定调色板中的颜色。
- 调色板项:调色板中的每个条目由RGB(红、绿、蓝)三个0 - 63的整数值组成,索引0控制屏幕背景颜色。
- 颜色示例:如(20,20,20)、(63,63,63)、(63,0,0)。
- 背景颜色设置:代码示例如下:
; 设置屏幕背景颜色为亮绿色
mov dx,3c8h ; 视频调色板端口
mov al,0 ; 索引0 (背景颜色)
out dx,al
mov dx,3c9h ; 颜色写入端口
mov al,0 ; 红色
out dx,al
mov al,63 ; 绿色 (强度 = 63)
out dx,al
mov al,0 ; 蓝色
out dx,al
; 设置屏幕背景颜色为白色
mov dx,3c8h ; 视频调色板端口
mov al,0 ; 索引0 (背景颜色)
out dx,al
mov dx,3c9h ; 颜色写入端口
mov al,63 ; 红色 = 63
out dx,al
mov al,63 ; 绿色 = 63
out dx,al
mov al,63 ; 蓝色 = 63
out dx,al
3.5 鼠标编程
| 功能 | 说明 | 代码示例 |
|---|---|---|
| 功能0 | 用于重置鼠标 |
mov ax,0 ; 重置鼠标
int 33h ; 调用BIOS
cmp ax,0 ; 鼠标不可用?
je MouseNotAvailable ; 是: 显示错误信息
| 功能1和2 | 用于隐藏鼠标指针 |
mov ax,2 ; 隐藏鼠标指针
int 33h
| 功能3 | 用于获取鼠标位置和状态 |
mov ax,3 ; 获取鼠标位置和状态
int 33h
mov mouseX,cx
mov mouseY,dx
| 功能4 | 用于设置鼠标位置 |
mov ax,4 ; 设置鼠标位置
mov cx,100 ; X值
mov dx,400 ; Y值
int 33h
| 功能5 | 用于获取按键按下信息 |
mov ax,5 ; 获取按键按下信息
mov bx,0 ; 左键ID
int 33h
test ax,1 ; 左键当前按下?
jne Button1 ; 是: 跳转到标签
| 功能6 | 用于获取按键释放信息 |
mov ax,6 ; 获取按键释放信息
mov bx,1 ; 按键ID
int 33h
test ax,2 ; 右键释放?
jz skip ; 否 - 跳过
mov mouseX,cx ; 是: 保存坐标
mov mouseY,dx
skip:
| 功能8 | 用于设置垂直限制 |
mov ax,8 ; 设置垂直限制
mov cx,200 ; 下限
mov dx,400 ; 上限
int 33h
| 功能7 | 用于设置水平限制 |
mov ax,7 ; 设置水平限制
mov cx,300 ; 下限
mov dx,600 ; 上限
int 33h
- 坐标计算:假设字符单元为8×8像素,可计算鼠标在字符单元中的坐标,如(8 * 20, 8 * 10),将鼠标移到单元中心的坐标为(180, 124)。
- 发明历史:鼠标由Douglas Engelbart于1963年在斯坦福研究所发明。
4 高级MS - DOS编程
4.1 定义段
- 段声明:使用SEGMENT声明段的开始,ENDS声明段的结束。
- 地址获取:可获取数据标签或代码标签的段地址。
-
假设指令:ASSUME指令帮助汇编器在汇编时计算标签和变量的偏移地址,如
assume DS:myData。 - 对齐类型:包括BYTE、WORD、DWORD、PARA和PAGE。
- 组合类型:如PRIVATE、PUBLIC、MEMORY、STACK、COMMON和AT。
- 数据类型:DWORD有特定用途。
-
组合方式:组合类型告诉链接器如何组合同名段,可使用AT组合类型定义特定地址的段,如
bios SEGMENT AT 40h。 - 类类型:段的类类型提供了另一种组合段的方式,同名类类型的段会一起加载。
-
代码示例:如
mov al,es:[di]。 - 地址情况:第三个段可能从地址1A060h开始。
4.2 运行时程序结构
- 程序执行:命令处理器先检查当前目录中是否有COM扩展名的文件,有则执行,否则按特定步骤处理。
- 程序类型:应用程序加载到最低640K内存,执行完后自动卸载。
- 段前缀:涉及程序段前缀,其偏移2Ch处有特定信息。
- COM程序:是单段MS - DOS程序,存储为COM文件时是内存中的二进制映像。
- 程序类型:有Tiny类型。
- 编译选项:使用/T选项。
- 内存大小:COM程序使用64KB内存段,不够高效。
- 段数量:通常为一个。
- 寄存器设置:所有段寄存器在程序内偏移为0,程序加载到可用段位置。
- 偏移设置:ORG指令可为后续标签或指令分配特定偏移,如COM程序开头的ORG 100h。
- 加载模块:涉及加载模块的概念。
- 寄存器指向:DS和ES指向程序段前缀区域。
- 内存分配:MS - DOS默认分配所有可用内存,除非EXE头限制。
- 统计工具:EXEMOD程序可显示程序内存使用统计信息并修改EXE头设置。
- 重定位项:运行EXEMOD程序并传入EXE文件名,最后一行显示重定位项数量。
4.3 中断处理
- 中断显示:显示“Abort, retry, or ignore?”消息并终止当前程序。
- 中断地址:中断处理程序由32位段/偏移地址指向。
- 特定地址:地址0000:0040h对应特定中断。
- 控制器芯片:8259可编程中断控制器芯片起重要作用。
- 标志操作:CLI指令清除中断标志,STI指令设置中断标志。
- 优先级:IRQ 0优先级最高。
- 中断顺序:键盘(IRQ 1)优先级高于磁盘驱动器(IRQ 14),文件创建前键盘中断优先处理。
- 中断调用:INT 9h用于键盘输入处理。
- 中断返回:中断处理程序末尾的IRET指令将控制权返回给中断发生时运行的代码。
- 功能调用:功能25h和35h用于特定操作。
- 程序区别:中断处理程序和内存驻留程序有区别,内存驻留程序不一定是中断处理程序。
- 驻留程序:终止并驻留(TSR)程序通过调用INT 21h功能31h部分驻留内存。
- 移除方式:可通过重启计算机或使用特殊实用程序移除TSR程序。
- 特殊处理:中断处理程序结束时可执行JMP到中断向量中存储的地址。
- 快捷键:Ctrl + Alt + 右Shift + Del有特定作用。
5 相关指令及编程基础概念补充
5.1 基础指令
| 指令 | 说明 |
|---|---|
__asm
指令
| 在 Visual C++ 中有特定用途,用于嵌入汇编代码 |
AAA
指令
| ASCII 加法调整指令 |
AAD
指令
| ASCII 除法前调整指令 |
AAM
指令
| ASCII 乘法后调整指令 |
AAS
指令
| ASCII 减法后调整指令 |
ADC
指令
| 带进位加法指令 |
ADD
指令
| 加法指令,可用于变量相加等操作 |
CBW
指令
| 字节转换为字指令 |
CDQ
指令
| 双字转换为四字指令 |
CMP
指令
| 比较指令 |
CMPSB
、
CMPSD
、
CMPSW
指令
| 字符串比较指令 |
CALL
指令
| 调用子程序指令 |
5.2 编程概念
-
地址相关
- 地址总线 :用于传输地址信息。
- 地址空间 :规定了系统可寻址的范围。
- ADDR 运算符 :有特定的运算功能。
-
数据类型
- BYTE :用于定义字节类型的数据。
- Character constant :字符常量,在编程中有特定的存储和使用方式。
-
程序结构
- .CODE 指令 :用于定义代码段。
- Code label :代码标签,用于标识代码位置。
- Code segment :代码段,是程序代码存储的区域。
5.3 条件与循环指令
-
条件指令
-
.BREAK 条件:用于在特定条件下跳出循环。 - CMP 指令 :通过比较影响标志位,结合跳转指令实现条件分支。
-
-
循环指令
-
LOOPE(等于时循环) -
LOOPNE(不等于时循环) -
LOOPNZ(不为零时循环) -
LOOPZ(为零时循环)
-
5.4 条件汇编指令
条件汇编指令用于根据不同条件生成不同的汇编代码,包含以下几个方面:
-
布尔表达式
:用于条件判断。
-
默认参数初始化
:为参数提供默认值。
-
IF、ELSE、ENDIF 指令
:实现条件分支。
-
IFIDN 和 IFIDNI 指令
:用于字符串比较判断。
-
宏函数
:可定义和使用宏函数来简化代码。
5.5 编译器相关
- 编译器生成代码 :不同编译器生成的代码有其特点,需要了解其优化方式和生成规则。
- C 和 C++ 编译器 :在调用 C 和 C++ 函数时,需要遵循特定的调用约定。
- C 语言调用约定 :有特定的参数传递和返回值规则。
5.6 输入输出相关
-
控制台输入
- 控制台输入缓冲区 :用于存储用户输入的信息。
- 获取键盘状态 :可通过特定指令获取键盘的当前状态。
- 单字符输入 :实现单个字符的输入操作。
-
文件操作
-
关闭文件句柄
:使用特定功能关闭文件句柄,如
3Eh功能。 - 文件读写 :使用 INT 21h 的不同功能实现文件的读写操作。
-
关闭文件句柄
:使用特定功能关闭文件句柄,如
6 编程实践与示例
6.1 代码示例
-
数组操作
- 数组点积 :计算数组的点积,代码示例如下:
; 数组点积示例代码
; 假设已经定义了数组和相关变量
; 实现数组点积的逻辑代码
- **数组求和**:计算数组元素的和,代码示例如下:
; 数组求和示例代码
; 假设已经定义了数组和相关变量
; 实现数组求和的逻辑代码
- **数组平方根求和**:计算数组元素平方根的和,代码示例如下:
; 数组平方根求和示例代码
; 假设已经定义了数组和相关变量
; 实现数组平方根求和的逻辑代码
- 表达式计算 :实现复杂表达式的计算,代码示例如下:
; 表达式计算示例代码
; 假设已经定义了相关变量
; 实现表达式计算的逻辑代码
6.2 排序算法
-
冒泡排序
- 伪代码 :
for i = 0 to n - 1
for j = 0 to n - i - 1
if array[j] > array[j + 1]
swap array[j] and array[j + 1]
- **汇编语言实现**:
; 冒泡排序汇编语言实现
; 假设已经定义了数组和相关变量
; 实现冒泡排序的逻辑代码
6.3 搜索算法
-
二分搜索
- 算法 :
low = 0
high = n - 1
while low <= high
mid = (low + high) / 2
if array[mid] == target
return mid
else if array[mid] < target
low = mid + 1
else
high = mid - 1
return -1
- **测试程序**:
; 二分搜索测试程序
; 假设已经定义了数组和相关变量
; 实现二分搜索测试的逻辑代码
6.4 函数调用示例
-
调用 C 和 C++ 函数
- 汇编语言模块 :
; 调用 C 和 C++ 函数的汇编语言模块示例
; 假设已经包含了必要的头文件和声明
; 实现函数调用的逻辑代码
-
调用 C 库函数
- 示例代码 :
; 调用 C 库函数的示例代码
; 假设已经包含了必要的头文件和声明
; 实现函数调用的逻辑代码
6.5 内存操作示例
-
内存映射图形操作
- 设置背景颜色 :前面已经给出了设置亮绿色和白色背景颜色的代码示例。
- 像素操作 :可根据调色板和坐标信息对像素进行操作。
6.6 中断处理示例
- 自定义中断处理程序
; 自定义中断处理程序示例
; 假设已经定义了相关的中断向量和处理逻辑
; 实现中断处理的逻辑代码
6.7 程序运行流程示例
graph TD
A[开始] --> B[检查COM文件]
B -- 找到COM文件 --> C[执行COM程序]
B -- 未找到COM文件 --> D[按特定步骤处理]
C --> E[程序结束]
D --> E
通过以上对 16 位 MS - DOS 编程及相关技术的详细介绍,涵盖了从基础的 MS - DOS 编程、磁盘操作、BIOS 级编程到高级的 MS - DOS 编程等多个方面,同时给出了丰富的代码示例和操作说明,希望能帮助读者更好地理解和掌握这些编程技术。在实际应用中,可根据具体需求选择合适的技术和方法进行开发。
超级会员免费看
9

被折叠的 条评论
为什么被折叠?



