DOS环境搭建

DOS环境搭建有几种方式,不过主要的环境都是依赖于DOSBox,有条件可以直接在xp上运行,直接就有dos环境,著需要安装MASM工具即可实现编译调试了。

方式1(win10下安装DOSBox+MASM)

DOXBox下载

汇编MASM工具

安装DOSBox,之后配置MASM,将下载的MASM复制到自己的文件夹下,其中MASM.EXE文件是用来编译的,LINK.EXE是用来链接的,这两个是必须的。debug.exe是用来调试的,edit.com可以用来写汇编语言代码(推荐记事本来编写汇编语言代码)

配置完后进入DOSBox首先是挂载盘符,这里我们编辑DOSBox的配置文件(C:\Users\xxx\AppData\Local\DOSBox\dosbox-0.74-3.conf)实现启动自动挂载,自动编译2.masm文件:

mount d d:\software\DOSBox-0.74-3\MASM
d:

masm 2.asm;
link 2.obj;

之后当你编辑完汇编后,可以重启DOSBox来实现自动编译。

方式2(vscode插件一键配置)推荐

DOSBox的配置较为麻烦,这里带大家在我们熟知的VS Code里一键安装一个汇编语言的模拟、写程序以及运行调试的环境;这种方式是一键式便捷安装的方式,只需要点击安装vscode插件即可。

第一步:安装

打开VS Code中的扩展栏,并搜索MASM,找到MASM/TASM这个插件,并安装即可;
这个插件会把我们所需要的dosbox, dosbox-x, jsdos以及汇编编译器MASM都安装好,也不需要我们再去挂载之类的操作;

第二步:编写一个helloworld的汇编程序

DATA   SEGMENT
PRINT  DB "Hello World!", 0AH, 0DH, '$'
DATA   ENDS
STACK  SEGMENT   STACK 
       DW  20  DUP(0)
STACK  ENDS
CODE   SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STACK
START:
        MOV AX, DATA                         
        MOV DS, AX
        MOV DX, OFFSET  PRINT
        MOV AH, 09
        INT 21H
        MOV AH, 4CH
        INT 21H
CODE   ENDS
END    START

在VS Code右下角选择assembly(DOS)的文本格式。

第三步:编译,链接,运行/调试

在.asm文件左下角,点击dosbox MASM,会弹出选择框,让你选择编译环境,这里提供了很多环境,这里我们选择dosbox MASM,后面会说明这几个环境有啥区别。

在选择完编译环境后,右键选择运行还是调试,随后就会打开一个dos环境编译、连接、运行或调试你的程序,当然你也可以在环境里做一些其他你想做的事。

从第一步我们知道,这个插件帮我们安装了doxbox, dosbox-x和jsdos三个环境,我们来看一下这三个环境的区别是什么:

dosbox, dosbox-x, jsdos都是和dosbox类似的dos模拟环境。

  1. jsdos提供类似于在网页中的效果,可自行切换尝试
  2. dosbox的效果,就是打开这个软件自动编译运行或调试
  3. dosbox-x的效果,就是DOSbox的升级版,汇编的段标识符格式也要有点区别(因为DOSbox-x用的是TASM汇编编译器),调试界面优化,类似于简易的windbg界面(看内存不是很方便)

MASM DEBUG常用命令

命令功能示例
R查看、改变CPU寄存器的内容r
D查看内存中的内容d 73a:100
E改写内存中的内容e 73a:100
U将内存中的机器指令翻译成汇编指令,也就是反汇编u 73a:100
T执行一条机器指令 (类似于VS中的逐语句)t
A以汇编指令形式在内存中写入一条机器指令a 出车输入指令 再回车结束输入
G类似于设置断点并执行至该断点g 73a:100
P单步或多步执行指令(遇到循环等会执行多步命令,类似于VS中的逐过程)p

DOS编译链接

DOS介绍

DOS环境是一个简单的16位操作系统平台

  • 设计运行于8086和8088处理器
  • 也可运行于IA-32处理器的实地址工作方式
    32位Windows操作系统模拟有一个MS-DOS环境
  • 基于Windows保护方式的一个8086仿真环境

DOS特点

DOS是单用户单任务操作系统
DOS系统只有一个特权级别
应用程序可以访问任意资源

  • 使用IO指令直接对外设端口操作
  • 修改任何主存数据
  • .......

DOS编程的注意事项

16位DOS环境默认采用16位操作数尺寸

  • 主要使用16位或8位寄存器、操作数和寻址方式
  • 堆栈以16位为单位压入PUSH和弹出POP数据
    IA-32处理器的实地址工作方式
  • 还允许使用32位寄存器、操作数和寻址方式
  • 可以使用大多数新增的32位通用指令

实地址存储模型

主存空间1MB( =2^20 B) : 00000H一FFFFFH
程序设计时分段管理,但有两个限制:

  • 每个段最大为64KB
  • 段只能开始于低4位地址全为0的物理地址处

逻辑地址和物理地址

逻辑地址=段地址∶偏移地址

  • 16位段寄存器保存20位段起始地址的高16位
  • 偏移地址也用16位数据表示
    物理地址=段地址×16+偏移地址

16位存储器寻址方式
基址寄存器+变址寄存器+位移量

多种主存寻址方式

mov ax,wvar      ;直接寻址
mov ax,[bx]      ;寄存器间接寻址
mov ax,[bp+4]    ;寄存器相对寻址
mov ax,[bx+si]   ;基址变址寻址
mov ax,[bx+di-2] ;相对基址变址寻址

DOS应用编程

16位DOS源程序编程框架

include io16.inc ;包含16位输入输出文件
       .data        ;定义数据段
       ...          ;数据定义(数据待填)
       .code        ;定义代码段
start: mov ax,@data ;程序执行起始位置
       mov ds,ax   
       ...          ;主程序(指令待填)
       exit 0       ;程序正常执行终止
       ...          ;子程序(指令待填)
       end start    ;汇编结束

io16.inc

DOS应用程序的包含文件
   - 提供基本声明等语句
   - 用于封装源程序文件的细节内容
需要配合16位IO库文件IO16.LIB
   - 共同保存于当前目录

设置数据段寄存器

DOS分段管理程序
汇编和连接程序设置了CS:IP和SS:SP
DS和ES需要用户程序设置

       mov ax,@data 
       mov ds,ax 

DOS系统调用

DOS系统调用步骤

  1. 在AH寄存器中设置系统功能调用号
  2. 在指定寄存器中设置入口参数
  3. 用中断调用指令(INT N)执行功能调用
  4. 根据出口参数分析功能调用执行情况

DOS基本功能调用(INT 21H)

子功能号功能参数
AH=01H从标准输入设备输入一个字符AL=输入字符的ASCII码
AH=02H从标准输入设备输出一个字符DL=字符的ASCII码
AH=09H从标准输入设备输入一个字符串DX=字符串地址
AH=4cH程序终止AL=返回代码

退出DOS

mov ax,4c00h
int 21h
调用DOS 4CH号功能,实现执行结束退出

指令调用

DOS功能使用"INT N"指令调用
中断调用方法还应用于

  • 基本输入输出系统ROM-BIOS
  • Linux系统功能
mov ah,子功能号
int 21h 

输入输出编程

输入指令(IN)

数据从I/0接口(外设)输入到处理器

IN ALIAX/EAX,i8/DX
例如: in al,21h
      in al,dx

输出指令(OUT)

数据从处理器输出到I/0接口(外设)

OUT i8/DX,ALIAX/EAX
例如: out 21h,al
      out dx,al

I/O直接寻址

I/0指令中直接提供I/0地址

  • IA-32处理器只能直接提供8位I/0地址
  • 只能寻址最低256个I/0地址(00~FFH)>用i8表示I/0地址
  • 表达形式与立即数一样
IN ALIAX/EAX,i8/DX
OUT i8/DX,AL/AX/EAX

I/O间接寻址

I/0指令中通过寄存器间接提供I/0地址

  • IA-32处理器用DX寄存器保存访问的I/0地址
  • 可寻址全部I/0地址(0000~一FFFFH)
    直接书写成DX,表示I/0地址
  • 不需要用中括号
IN ALIAX/EAX,i8/DX
OUT i8/DX,ALIAX/EAX

CMOS RAM

CMOS RAM是使用CMOS技术的存储器芯片

  • PC机用以保存配置信息以及实时时钟断点后由
  • 后备电池供电,避免信息丢失>具有64个字节存储容量
  • 通过两个I/O地址访问

实例

;输入一个小写字母,自动转换为大写字母
STACK   SEGMENT  STACK          ;;定义堆栈段
        DB 100 DUP (?)          ;;开辟100个存储单元
STACK  	ENDS			;	;堆栈段结束

CODE  	SEGMENT		;		;定义代码段
      	ASSUME  CS:CODE , SS:STACK
START:  MOV  AH ,01H      ;;1号调用,从键盘输入一字符存入AL
        INT  21H
        SUB  AL ,20H     ;;将AL中字符的ASCII码减去20H变成大写字母
        MOV  DL ,AL		;;结果送DL
        MOV  AH ,02H 	       ; ;2号调用,在屏幕上显示DL中的内容
        INT  21H 
        MOV  AH,4CH		;;返回DOS 
        INT  21H 					
CODE    ENDS			;;代码段结束
        END  START		;;程序汇编结束

参考

https://blog.csdn.net/kking_edc/article/details/109165963