 安装TASM 5.0很简单，您只需要下载本站[相关工具]中的"TASM50.zip"文件，解压后在Windows9x/NT下执
行"INSTALL.EXE"即可开始安装。

    1.如果你在安装TASM5.0之后安装Delphi 1.0或Borland C++ 4.x及更高版，你需要手动更改系统的设置以
使这些产品可以共存于同一个系统中——检查“System.ini”文件的[386Enh]一节是否有多个TDDEBUG.386驱动
项。删除多余的TDEBUG.386项，保证只有这个版本的TDDEBUG.386装入。这可通过检查[386Enh]小节来确认，如
果安装完TASM 5.0，未见其更改，请手工在System.ini文件的[386Enh]小节中增加：
         device=c:\tasm\bin\windpmi.386——支持TASM5.0的32位工具。
         device=c:\tasm\bin\tddebug.386——支持我们的调试器。

    2.配置Windows NT命令行提示符（相当于Windows9x的MS DOS方式）
    在NT命令行提示符下运行16位保护方式程序如tlink，需要参照以下所示在CONFIG.NT文件中增加一行：
         ntcmdprompt

    3.定制安装TASM5.0时的选项：
      16-bit command line tools [3085K]
         安装16位工具（TASM、TLINK等），这也是最小化安装的默认选项。(建议不安装)
      32-bit command line tools [3163K]
         安装32位工具（TASM32、TLINK32）
      Turbo Debugger for DOS [1041K]
         安装Turbo的DOS调试工具，也是最小化安装的默认选项。(建议不安装)
      Turbo Debugger for Windows [1533K]
         安装Turbo的Windows调试工具及相关的其它调试工具。
      Turbo Debugger for Win32 [1502K]
         安装Turbo的Win32程序调试工具。
      Examples [580K]
         安装Borland TASM的例程。
      Documentation Files [6K]
         安装说明文档。

    4.如何在Windows9x/NT下运行TASM32等32位工具
    TASM5.0安装程序会在Windows程序管理器下建立TASM5.0组，但是它不会为那些在命令行提示符下运行的工
具建立相应的PIF文件。TASM.EXE等16位可执行工具不需要特别的PIF文件就能够运行在常规的Windows MS-DOS
方式下。但要从Windows MS-DOS方式下运行TASM32等32位工具，则需要为其建立相对应的PIF文件。最简单的方
法是利用B32TOOLS.PIF（在TASM\BIN目录下）在Windows MS-DOS方式下运行这些32位工具—在WIndows下双击
B32TOOLS.PIF,会激活一个DOS窗口，之后可以在其下运行TASM32.EXE和TLINK32等32位工具。
　
TASM 5.0 文件清单
　
X:\TASM 

<dir> 
BIN 

<dir> TASM5.0工具包执行文件(77个) 
TD.PIF 为调试工具TD生成一个供其运行的命令提示符环境 
B32TOOLS.PIF ★★定义一个Tasm5.0 32位工具运行的命令提示符环境 

TASM.EXE 16位实模式汇编编译器 
TASMX.EXE 16位保护模式汇编编译器 
TASM32.EXE ★★★32位保护模式汇编编译器 
TLINK.EXE 16位连接程序(只能连接16位的目标文件) 
TLINK32.EXE ★★★32位连接程序(只能连接32位的目标文件) 
BRC.EXE 16位的资源编译/绑定程序 
BRCC.EXE 16位的资源编译程序 
BRC32.EXE ★★★32位的资源编译/绑定程序 
BRCC32.EXE ★★32位的资源编译程序(单纯的资源编译器，功能与BRC32一致) 
MAKE.EXE ★★★一个能调用MAKEFILE并按此文件的规定完成编译、链接的工具 
MAKER.EXE MAKE的NT版(在WindowsNT下运行MAKE程序遇到困难时用它试试) 
TLIB.EXE ★★★Tasm库管理工具 
IMPLIB.EXE ★★★由动态链接库生成相应引入库的工具(一个绝对有用的工具) 
IMPDEF.EXE ★★由动态链接库生成其模块定义文件的工具 
H2ASH.EXE 由C/C++头文件生成Tasm头文件(包含文件)的转换工具(16位) 
H2ASH32.EXE ★★由C/C++头文件生成Tasm头文件(包含文件)的转换工具(32位) 
WINSTUB.EXE 给Windows程序附加一个DOS头(这样在DOS下运行PE程序会出现提示) 
MAKESWAP.EXE 虚拟内存工具(出现内存溢出错误时可以用它建立一个磁盘交换文件) 
OBJXREF.EXE 将OBJ转化为REF文件的转换工具 
RLINK.EXE 资源连接器(把编译后的资源文件同可执行文件装配到一起) 
TDUMP.EXE ★★文件观察器(主要用于获取.EXE或.OBJ或.LIB文件的相关信息) 
THUNK.EXE 微软Thunk工具，主要用于16/32位程序的转换(详细说明见EXAMPLES) 
TOUCH.EXE 设置列表中文件的日期、时间为当前或指定日期、时间的工具 
JITIME.EXE 即时调试安装工具 
GROUPS.EXE 在Windows的程序管理器下建立Tasm5.0的程序组 
32RTM.EXE （没用过） 
TDSTRIP.EXE 符号表解析程序(for 16位) 
TDSTRP32.EXE 符号表解析程序(for 32位) 
TDMEM.EXE TD内存观察器(仅运行于DOS方式下) 
TDRF.EXE TD远程文件传输工具 
TD.EXE DOS程序调试工具(集成环境) 
TDW.EXE Windows程序调试工具(集成环境) 
TD32.EXE Win32程序调试工具(集成环境) 
TDINST.EXE TD.EXE的配置工具(集成环境) 
TDWINST.EXE TDW.EXE的配置工具(集成环境) 
TD32INST.EXE TD32.EXE的配置工具(集成环境) 
TDWINI.EXE TD显示动态连接库配置工具(for Windows) 
TDREMOTE.EXE 远程调试工具(for DOS) 
WREMOTE.EXE 远程调试工具(for Windows) 
WRSETUP.EXE 远程驱动设置程序(for Windows) 
GREP.COM （没用过） 

WINDPMI.386 驱动程序，应该增加到“System.ini”文件[386Enh]一节 
TDDEBUG.386 调试程序的驱动程序 
BUILTINS.MAK ★内建makefile文件(如果用户缺省makefile文件则MAKE.EXE调用它) 

TLINK.CFG TLINK的配置文档 
TLINK32.CFG TLINK32的配置文档 

TASM.HLP Turbo Assembler帮助文件(Windows帮助文件格式) 
TDWINI.HLP TD显示动态连接库配置工具帮助文件 
TDHELP.TDH TD.EXE的帮助文件 
TDWHELP.TDH TDW.EXE的帮助文件 
TD32HELP.TDH TD32.EXE的帮助文件 

RTM.EXE 非独立工具，由其他工具调用(相当于一个覆盖文件) 
TDCON32.EXE 非独立工具，由TDW.EXE调用(相当于一个覆盖文件) 
DPMI16BI.OVL 覆盖文件 
DPMI32VM.OVL 覆盖文件 
RLINK32.DLL 动态连接库 
RW32CORE.DLL 动态连接库 
RWRES.DLL 动态连接库 
BWCC.DLL 动态连接库 
TDKBD32.DLL 动态连接库 
TDVID16.DLL 动态连接库 
TDWINTH.DLL 动态连接库 
DUAL8514.DLL 显示驱动动态连接库 
STB.DLL 显示驱动动态连接库 
SVGA.DLL 显示驱动动态连接库 
SVGA32.DLL 显示驱动动态连接库 
TDWGUI.DLL 显示驱动动态连接库 

HELP.ICO 图标文件 
TDDOS.ICO 图标文件 
TDOSINST.ICO 图标文件 
TD32.ICO 图标文件 
TD32INST.ICO 图标文件 
TDW.ICO 图标文件 
TDWINST.ICO 图标文件 
WORKOPT.DOS （不知道，名称含义好象是工作选项？） 
INCLUDE 

<dir> TASM 5.0包含文件(3个)
(建议把你的包含文件放置于此) 
MMSYSTEM.INC 16位包含文件 
TOOLHELP.INC 16位包含文件 
WINDOWS.INC 16位包含文件 
LIB 

<dir> TASM 5.0库文件(2个)
(建议把你的引入库文件放置于此) 
IMPORT.LIB 16位引入库文件 
IMPORT32.LIB 32位引入库文件 
EXAMPLES 

<dir> TASM 5.0例程 
(其下文件略) . 
DOC 

<dir> TASM 5.0说明文档(10个) 
MAKE.TXT MAKE和MAKER的使用说明 
TDUMP.TXT TDUMP的使用说明 
TLIB.TXT IMPLIB、IMPDEF和TLIB的使用说明 
TLINK.TXT TLINK(TLINK32),TLINK.CFG,Response files,模块定义文件使用说明 
TSM_HELP.TXT 本文件解答了Turbo Assembler的一些常见问题 
TSM_UTIL.TXT TDSTRIP(TDSTRP32)、TDMEM、TDWINI、TDRF使用说明 
TD_ASM.TXT TURBO DEBUGGER Assembler-level debugging 
TD_HDWBP.TXT TURBO DEBUGGER USING THE HARDWARE DEBUGGING FEATURES 
TD_RDME.TXT TURBO DEBUGGER Turbo Debugger Readme file 
TD_UTILS.TXT H2ASH 
UNPAK.EXE . 解包程序 
README.COM . 安装完成时运行一次，以后好象没什么作用了 
TSM_INST.TXT . TASM 5.0安装说明文档 
TSM_RDME.TXT . TASM 5.0总概 
　
TASM 5.0 技术支持及升级
　
宝蓝(Borland)站点：http://www.borland.com/
宝蓝TASM网页：http://www.borland.com/borlandcpp/cppcomp/tasmfact.html
宝蓝TASM新闻组：news://newsgroups.borland.com/borland.public.tasm/
　
最小的TASM 5.0 工具包
　
如果您想用汇编语言编制一个Windows程序，那么您的TASM 5.0工具包至少需要包含以下文件：
            TASM32.EXE                ;编译器
            TLINK32.EXE               ;连接器
            BRC32.EXE                 ;资源编译器
            TLIB.EXE                  ;库管理工具
            IMPLIB.EXE                ;参见上面
   当然，如果你不想用最后两个工具,可以用Turbo ASM5.0的“import32.lib”取代它们,只是前者是“渔”，
后者是“鱼”，您要哪个呢？最后你必须再拥有一个文本编辑器——最简单的就是Windiows9x的记事本了，可是
不十分趁手，因为编写程序总希望编辑器能有记忆、块拷贝功能，不过不要着急，本站终究要推出几个用汇编编
写的实用程序，其中就有9x&2K下的汇编语言编辑器了！
　
编译器TASM/TASMX/TASM32简介

[暂只介绍TASM32]

Turbo Assembler Version 5.0 Copyright (c) 1988, 1996 Borland International

Syntax: TASM32 [options] source [,[object] [,[listing] [,[xref]]]] [;]
句法：
TASM32 [选项] 源文件名 [,[目标文件名] [，[清单（或列表）文件名] [，[索引(或符号)表文件名]]]] [;]

说明：(句法英文行非原文，是本站根据实际修改而得，更能反映实际情况)

1. “选项”可以是下面任意一项或几项的组合。请根据具体情况选用，也可不要。不过稍后你会发现，其中一些选项在编译Win32汇编语言程序时起着很重要的作用。翻译是我结合经验采用意译方式表述的，错误之处，还请指正。更详细的说明，将在论坛专题中一一说明和示例。 /a,/s Alphabetic or Source-code segment ordering
规定在生成目标文件时，按英文字母顺序还是源代码段顺序写段（默认为/s） 
/c Generate cross-reference in listing
在清单文件中产生交叉引用索引 
/dSYM[=VAL] Define symbol SYM = 0, or = value VAL
定义汇编程序符号（供条件编译使用，以使条件编译时得变量或信息的初始值可以通过TASM32
命令行传递获取） 
/e,/r Emulated or Real floating-point instructions
创建防真的或实际的符点指令的代码 
/h,/? Display this help screen
在屏幕上显示本帮助信息 
/iPATH Search PATH for include files
设置包含文件搜索路径 
/jCMD Jam in an assembler directive CMD (eg. /jIDEAL)
输入一个汇编指令（如：/jIDEAL） 
/kh# Hash table capacity # symbols
散列表容纳#个符号 
/l,/la Generate listing: l=normal listing, la=expanded listing
规定汇编清单文件：l=正常清单文件，la=扩充的清单文件 
/ml,/mx,/mu Case sensitivity on symbols: ml=all, mx=globals, mu=none
设置编译时对符号大小写敏感度：ml=全部敏感，mx=对公共或外部名称大小写敏感，mu=不敏感 
/mv# Set maximum valid length for symbols
设置符号的最大有效长度（符号超过设置值长度部分将被忽略） 
/m# Allow # multiple passes to resolve forward references
允许第#次编译（扫描）可以向前引用（编译一般采用二次扫描，所以一般使用：/m1、/m2） 
/n Suppress symbol tables in listing
取消清单文件中的表 
/os,/o,
/op,/oi Object code: standard, standard w/overlays, Phar Lap, IBM
规定目标代码格式，分别对应：标准格式，标准w/overlays格式，Phar Lap格式和IBM格式 
/p Check for code segment overrides in protected mode
检查非纯代码（实模式下可写代码段，而保护模式下就会产生问题，保护模式下写代码段一般是
通过别名段描述符来实现的，参见‘例程精选’中的‘Pm09.zip’——题外话，呵呵） 
/q Suppress OBJ records not needed for linking
在目标文件取消那些和链接无关的数据记录 
/t Suppress messages if successful assembly
如果编译成功则取消所有信息 
/uxxxx Set version emulation, version xxxx
设置版本冲突检测 
/w0,/w1,/w2 Set warning level: w0=none, w1=w2=warnings on
设置出错告戒级别 
/w-xxx,/w+xxx Disable (-) or enable (+) warning xxx
使不能(/w-)或使能(/w+)出错警戒 
/x Include false conditionals in listing
在清单文件中包含假条件（条件汇编有用：可以在清单文件中包括不符合条件分支的代码） 
/z Display source line with error message
在错误信息中显示源代码行 
/zi,/zd,/zn Debug info: zi=full, zd=line numbers only, zn=none
调试信息：zi=全部，zd=仅有行号，zn=无 


2. “源文件名”，必选项，是你用任意文本编辑器编写的汇编语言程序文件的名称，文本格式。如果该文件使用
的是推荐扩展名“ASM”，式中可以不输入文件名的扩展部分。当然，你也可以指定其它扩展名，但在式中一定要
输入程序文件的全名——建议源程序使用推荐扩展名。

3. “目标文件名”，可选项，是我们编译的目的，供链接程序链接装配时使用，二进制格式。如果编译正确，一
个目标文件就会建立。如果你在式中未指定名称（包括扩展名），编译程序就会自动以“源程序文件名”+
“.OBJ”作为它的文件名（默认），否则就按你指定的——建议采用默认的。

4. “清单文件名”，也称“列表文件名”，可选项，便于我们查找源程序中的各种错误，文本格式。默认扩展名
为“.LST”。

5. “索引表文件名”，也叫“符号表文件名”，可选项，其中包含了程序中的各种符号、码段等信息，二进制格
式，默认扩展名为“.XRF”。为了能阅读这种文件，我们应该使用CREF命令将其转换为文本文件。CREF命令最常
用的格式是：
CREF [符号表文件名];


示例：
TASM32 myfile,,,
按默认方式，编译"myfile.asm"文件，生成"myfile.obj"、"myfile.lst"和"myfile.crf"文件。

TASM32 myfile;
按默认方式，编译"myfile.asm"文件，只生成"myfile.obj"文件。

TASM32 /v /z myfile,,;
编译期间将全部状态信息和出错信息显示在屏幕上，并生成"myfile.obj"、"myfile.lst"文件。
　

汇编语言上机指导及例示

作者：
作者网站：
文章源自：
收藏日期：2003-09-23
　
   
   从如何建立源文件到进行调试作下简要的介绍，并配例题说明。由于本人水平有限，在下文在如有错误及可以进一步修改的地方请大家指出
汇编语言上机过程： 
一、上机前的软件准备：
MS-DOS操作系统（如：MSDOS6.22 , MSDOS7.0 等）
文本编辑器 （如：EDIT.COM , TURBO.EXE , TC.EXE , C.EXE 等）
汇编程序 （如：MASM.EXE , ASM.EXE 等）
连接程序 （如：LINK.EXE 等）
调试程序 （如：DEBUG.EXE 等）

二、汇编程序建立过程:

　


a.建立汇编源程序─通过───→b.编译为目标文件─　↓┬─→d.连接为可执行文件
　　↑　　　　　　　　　　　　　　　　　　　　 　 　
　　│ 　c.不通过，重新修改（语句错误）　　 　 　　　 　　　　　　↓　
　　├──────────────────────┘　 　　　　　↓
　　↑　　　f.不正确，用调试工具调试，重新修改（逻辑错误）　 　 　↓　
　　└────────────────────────────←e运行
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　 　↓正确
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　 g.完成


三、现在对（二）的每一个标有字母的过程(PROCEDURE)进行详细说明

PROCEDURE a:建立汇编源程序（即：建立 文件名.asm）
这个过程就相当于我们在纸上编写源程序代码一样，只不过是将纸变为了计算机，这个过程也称源代码录入。将源程序代码录入计算机的方法很多，下面将介绍具体方法。 
1.通过MD-DOS自带的EDIT.EXE文本编辑器进行输入，在DOS提示符下键入:EDIT回车,这时如果你系统内可调用时，EDIT的操作画面便会出现在屏幕上，你就可在提示下进行录入了，当录入完毕后，选择存盘并给你输入的文件起一个文件名，形式：filename.asm ；（其中filename为你起的文件名,由1-8个字符组成），asm 是为汇编程序识别而必须加上去的，不可更改。存盘后在DOS下可用DOS命令DIR来查看，如果看到了所存的文件存在，就可以进行进程b。
2.如果你的系统中没有EDIT，也可用你所熟悉的文本编辑器进行录入、编辑，如可用c语言和pascal语言的文本编辑器来编辑,最后将文件存为filename.asm的形式即可。

PROCEDURE b:编译目标文件（即：编译为.obj .lst .crf文件）
这个过程计算机将把你编的正确的源代码编译为机器语言、程序清单及交叉引用表的目标文件。如果此时你的程序有语句错误，系统将报错，并指出在第几行，什么类型的错误，你可根据提示去逐一修改。现介绍具体过程：
在DOS提示符下键入MASM filename回车
（注：你系统内的汇编程序为MASM.EXE,如果你系统的汇编程序为ASM.EXE时，便将命令变为ASM filename回车。其中filename为你刚才在PROCEDURE a 中建立的文件名）
这时汇编程序的输出文件可以有三个（分别：.obj .lst .crf)，便会出现三次提问，在这可以一路回车即可。下面显示的信息是源程序中的错误个数，如果为0则表示顺利通过，就可进行进程c。但如果不为0就说明有错误，并指出错误出现的行，可依据这个提示去进行修改。但如果错误太多还未等看清就显示过去了，可用如下命令形将错误信息存于一个你指定的文件，再用文本编辑器去查看。 MASM filename >filen （filen为你起的一个没用过的文件名，用以存放出错信息）以后可查看filen来得到出错信息。

PROCEDURE c:编译不通过,重新修改（错误类型：源程序语句不合法）
在执行过PROCEDURE b后，如有出错信息时，就要我们自己按PROCEDURE c去做，而不能跳跃到PROCEDURE d去，如果强行执行PROCEDURE d将无任何有效结果。
现在就开现找错吧！首先要清楚，在PROCEDURE b中检测出的错误均为每一条语句的语法或用法错误，它并不能检测出程序的逻辑设计（语句按排位置）错误，所以就要记好出错的行号。在记录行号后，就应再次执行PROCEDURE a，这时和操作应是打开已编好的源程序（以EDIT为例：在DOS提示符下键入：
EDIT filename.asm回车），依据行号进行修改并存盘，再次进行汇编，直至PROCEDURE b通过为止。便可继续向下执行PROCEDURE d。
下面给出一些常见出错信息，以便查对：

1、Register already defined 汇编内部出现逻辑错误
2、Unknown symbol type 在符号语句的类型中，有些不能识别的东西
3、Symbol is multi-defined 重复定义一个符号
4、Symbol not defined 符号没有定义
5、Syntax error 语句的语法与任何可识别的语法不匹配
6、Symbol is reserved word
企图非法使用一个汇编程序的保留字(例：定义add为一变量)
7、Not proper align/combine type SEGMENT参数不正确
8、One operand must be const 这是加法指令的非法使用
9、Operands must be same or 1 abs 这是减法指令的非法使用
10、Already have base register 试图重复基地址
11、Illegal size for item 引用的项的长度是非法的，（如：双字移位）
12、Illegal register value 指定的寄存器值不能放入“reg” 字段
13、Must be AX or AL 某些指令只能用AX或AL
14、Improper use of segment reg 段寄存器使用不合法（如：mov ds,0）
15、Division by 0 or overflow 给出一个用0作除数的表达式
16、value is out of range 数值大于需要使用的
17、CS register illeal usage 试图非法使用CS寄存器
18、DUP is too large for linker
DUP嵌套太长，以至于从连接程序不能得到所要的记录

PROCEDURE d:连接为可执行文件（即：连接为.exe 或.com文件）
在这个过程中一般没有意外，如果有也就是文件名打错了。
形式：在DOS提示符下： LINK filename 回车

PROCEDURE e:运行编译好的可执行文件
当PROCEDURE d通过后，会产生一个可执行文件，这时只需运行这个程序，看它是否按你所想象那样得出结果。在试运行期间，要尽量试一些临界状态，看 程序是否运行稳定、结果是否正确。如一切正常，便可进入PROCEDURE g了。
可最怕的是不OK，程序产生一些莫名其妙的结果（你可不要以为是你的计算机不听你的指挥，其实它是在一丝不苟地按照你编的程序执行。我以前总以为我的计算机出了毛病），如果是在考场上这时千万不要慌，稳住自己的情绪，先不要看计算机，静几分钟（反正时间多得是）。这时就要用到最关键、最常用的一步了，进行PROCEDURE f 。

PROCEDURE f:用调试工具调试，重新修改（逻辑错误）
在这我将介绍用DOS中自带的调试程序DEBUG.EXE来进行程序调试、检查错误.
首先我们要了解DEBUG的基本用法： 
1、用于调试程序时的输入格式：
DEBUG FILENAME.??? 回车
其中FILENAME是主文件名，???是扩展文件名，例如我们在此前已编译好了一个文件，它的名子为：djx.exe 要对它进行调试时就在DOS提示符下
打：DEBUG djx.exe 回车，便可见到 '-' 提示符，如无任何提示说明正确，可进行调试。
2、DEBUG调试过程中用到的DEBUG命令介绍：
（注：在指令中用 [] 括起来的内容可缺省）
1)D(Dump)显示指定内存单元内容（一般用来看数据数的内容，即DS段）：
格式：d[地址] 从[地址]指定的内存单元显示128个字节的内容
[地址]缺省时，显示上一个DUMP命令后面的内容 
d 地址范围 显示指定范围内的内存内容。
示例：-d100 显示从DS段100H开始的内容（以十六进制显示）

2)E(Enter)修改存储单元内容（一般在DS段）
格式：e 地址 [数据] 用给定的[数据]代替指定范围的存储单元内容
e 地址 修改一个指定内存单元的内容
示例：-e ds:200 'djx'FF00AA 就可将DS段从200开始至205的内容替
换为64 6A 78 FF 00 AA

3)G(GO)运行命令
格式：-g [=地址][断点地址1 [断点地址2 ...[断点地址10]]]
从指定[地址]开始执行程序（如地址缺省从当前CS:IP开始），运行至[断点地址1]停止，显示所有寄存器及标志位内容与下一条指令，如后面还有断点，可键入g,继续执行。
示例：-g001a 则执行从当前cs:ip至001a的指令
注意：地址设置必须从指令的第一字节设起。

4)T(Trace)执行一条语句
格式： -t [=地址] 从指定[地址]起执行一条语句后停下来,显示所有寄存器内容及标志位的值与下一条指令。如[地址]缺省则从当前CS：IP开始执行
-t [=地址][value] 从指定地址起执行value条指令后停止。

5)P(proceed)执行一个循环;一个软中断或call子过程
格式：-p [=地址][n]
示例: mov ah,02h
mov dl,41h
int 21h
此时用: -p 回车后系统将显示一个字符A,如果在这不用P,而改用T,那么系统将进入INT 21H的中断调用中，出不来，这时你会误以为你的程序编错了，一定注意!!

6)R(register)显示并可修改寄存器内容
格式：-r 显示所有寄存器内容
-r 寄存器名 修改指定寄存器内容(可改：AX,BX,CX,DX,SP,
BP,SI,DI,CS,DS,ES,SS,PC,IP,F)

7)U(Unassemble)反汇编
格式：-u [地址] 从指定[地址]反汇编32个字节，若[地址]缺省则从当前地址汇编32个字节。
-u 地址范围 对指定范围内的存储单元进行反汇编

以上是在调试程序中可能用到的DEBUG命令解释，DEBUG中还有其它命令，在检查程序中不会用到，就不再介绍了。

PROCEDURE g:程序编好，那就一切OK!!!交卷过关了!大吃、大睡。

下面给出一个有病句的程序，希望大家和我一起调试、修改并通过：
先执行PROCEDURE a编辑源程序
实现功能：在屏幕上显示：Hello world
My name is DJX
文件名：error.asm
行号： 源程序代码：

1 data segment
2 out1 db 'Hello world'
3 ax db 'My name is DJX'
4 data ens
5
6 code segment
7 assume cs:code;ds:data
8 lea dx,out1
9 mov ah,2
10 int 21h
11
12 mov dl,0ah
13 mov ah,2
14 int 21h
15 mov dl,0dh
16 moo ah,2
17 int 21h
18
19 lea dx,ax
20 mov ah,
21 int 21h
22 code ends

在编辑完执行PROCEDURE b用masm进行编译：masm error回车后显示如下：
Microsoft (R) Macro Assembler Version 5.00
Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved.

Object filename [error.OBJ]:
Source listing [NUL.LST]:
Cross-reference [NUL.CRF]:
End of file encountered on input file
error.ASM(23): warning A4085: End of file, no END directive
Open segments: DATA
error.ASM(3): warning A4016: Reserved word used as symbol: AX
error.ASM(4): error A2105: Expected: instruction or directive
error.ASM(16): error A2105: Expected: instruction or directive
error.ASM(19): error A2049: Illegal use of register
End of file encountered on input file
error.ASM(23): warning A4085: End of file, no END directive

51566 + 406450 Bytes symbol space free

2 Warning Errors
4 Severe Errors

说明这个程序有错误，并在第3,4,16,19,23行有错，
我们再执行PROCEDURE c去逐一检查
第三行：3 ax db 'My name is DJX'
它的错误在于AX不能作为变量名，更正：
3 out2 db 'My name is DJX'
注意刚才我们定义AX为变量时在后面的程序中用过'变量AX'在第19行
19 lea dx,ax
在出错报告中也报第19行错，因为不能将AX的有效地址赋给DX,更正：
19 lea dx,out2
这样一下就解决了两个错误
第四行：4 data ens
这行为一个段的结束，但语句漏打了字母，更正：
4 data ends
第十六行：16 moo ah,2
这行也是语句打错，更正：
16 mov ah,2
第二十三行：
出错信息：error.ASM(23): warning A4085: End of file, no END directive
说明本程序没有结束伪操作，更正：
加入：在第七、八行加入地址标志： start:
原23 end start

执行PROCEDURE a将源程序修改如下：

data segment
out1 db 'Hello world'
out2 db 'My name is DJX'
data ends

code segment
assume cs:code;ds:data
start:
lea dx,out1
mov ah,2
int 21h

mov dl,0ah
mov ah,2
int 21h
mov dl,0dh
mov ah,2
int 21h

lea dx,out2
mov ah,9
int 21h
code ends
end start

再次进行PROCEDURE b进行编译，屏幕显示：

Microsoft (R) Macro Assembler Version 5.00
Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved.

Object filename [error.OBJ]:
Source listing [NUL.LST]:
Cross-reference [NUL.CRF]:
51524 + 406492 Bytes symbol space free

0 Warning Errors
0 Severe Errors

本程序在语句上已无错误。
再执行PROCEDURE d连接为可执行文件(link error回车),屏幕显示：

Microsoft (R) Overlay Linker Version 3.60
Copyright (C) Microsoft Corp 1983-1987. All rights reserved.

Run File [ERROR.EXE]:
List File [NUL.MAP]:
Libraries [.LIB]:
LINK : warning L4021: no stack segment

这时error.exe可执行文件已存在，可以执行PROCEDURE e来运行看一看是否正确
在dos提示符下键入：error回车(小心!!!)
屏幕显示：乱码，并死机。reset My computer!
说明程序在逻辑上有错误，并且严重。
这是就要用PROCEDURE f,用调试工具调试，查找错误。
在DOS提示符下键入：debug error.exe回车
屏幕出现 - 提示符，这时就可以用DEBUG的命令来找错误了，
我首先用d命令来查看数据区和内容，发展所定义的两个字符串并不在数据段的段首，而在数据段内的100h位置上，这时才想起masm有一个不成文的规定，那就是在定义完数据段后，所定义的变量均向后100h个单元，需要我们将ds段寄存器置位，在程序的start:后面加上如下指令：(执行PROCEDURE a)
mov ax,data
mov ds,ax
再执行PROCEDURE b,PROCEDURE d,PROCEDURE e来运行程序，
屏幕显示：
换行
My name is DJX及乱码，并死机。（又要重新启动！）
再次执行PROCEDURE a检查程序，发现：
1.汇编语言有规定每个字符串应由$结尾
2.在输出第一个串的语句中的AH子功能号应为09H
将以上两点改正。
再执行PROCEDURE b,PROCEDURE d,PROCEDURE e来运行程序，
屏幕显示：
Hello world
My name is DJX并死机，不能返回DOS
原因分析，在程序中没有返回DOS的指令，更正：
用PROCEDURE a来进行编辑：
用DOS 21H中断的4cH子功能便可返回DOS，在code ends前加：
mov ah,4ch
int 21h
再执行PROCEDURE b,PROCEDURE d,PROCEDURE e来运行程序，
屏幕显示：
Hello word
My name is DJX
并返回DOS
成功！
这样一个程序就调试完成，并正确。
下面是正确的源程序：

data segment
out1 db 'Hello world$'
out2 db 'My name is DJX$'
data ends

code segment
assume cs:code;ds:data
start:
mov ax,data
mov ds,ax

lea dx,out1
mov ah,9
int 21h

mov dl,0ah
mov ah,2
int 21h
mov dl,0dh
mov ah,2
int 21h

lea dx,out2
mov ah,9
int 21h

mov ah,4ch
int 21h
code ends
end start

以上这个程序很简单，只是为了说明实现汇编语言的上机编程及调试过程，汇编语言须多练习才能掌握它的特点，以便顺利通过考试
 　


汇编教程：	　
DEBUG命令详解

作者：
作者网站：
文章源自：
收藏日期：2003-09-23
　
　
   DEBUG是DOS中的一个外部命令，从DOS 1.0起就带有此命令，因此可见此命令的重要性了。虽然此命令的功能非常强大，可以解决许多问题，可是对许多人来说，尤其是初学者来说，却非常不易掌握。因此，现将DEBUG的命令详细介绍一番，以让大家知道它的使用。
Debug:A（汇编）


直接将 8086/8087/8088 记忆码合并到内存。

该命令从汇编语言语句创建可执行的机器码。所有数值都是十六进制格式，必须按一到四个字符输入这些数值。在引用的操作代码（操作码）前指定前缀记忆码。


a [address]


参数

address

指定键入汇编语言指令的位置。对 address 使用十六进制值，并键入不以“h”字符结尾的每个值。如果不指定地址，a 将在它上次停止处开始汇编。

有关将数据输入到指定字节中的信息，请单击“相关主题”列表中的 Debug E（键入）。

有关反汇编字节的信息，请单击“相关主题”列表中的 Debug U（反汇编）。


说明

使用记忆码

段的替代记忆码为 cs:、ds:、es: 和 ss:。远程返回的记忆码是 retf。字符串处理的记忆码必须明确声明字符串大小。例如，使用 movsw 可以移动 16 位的字串，使用 movsb 可以移动 8 位字节串。


汇编跳转和调用

汇编程序根据字节替换自动将短、近和远的跳转及调用汇编到目标地址。通过使用 near 或 far 前缀可以替代这样的跳转或调用，如下例所示：

-a0100:0500
0100:0500 jmp 502 ; a 2-byte short jump
0100:0502 jmp near 505 ; a 3-byte near jump
0100:0505 jmp far 50a ; a 5-byte far jump

可以将 near 前缀缩写为 ne。


区分字和字节内存位置

当某个操作数可以引用某个字内存位置或者字节内存位置时，必须用前缀 word ptr 或者前缀 byte ptr 指定数据类型。可接受的缩写分别是 wo 和 by。以下范例显示两种格式：

dec wo [si]
neg byte ptr [128]


指定操作数

Debug 使用包括在中括号 ([ ]) 的操作数引用内存地址的习惯用法。这是因为另一方面 Debug 不能区分立即操作数和内存地址的操作数。以下范例显示两种格式：

mov ax,21 ; load AX with 21h
mov ax,[21] ; load AX with the
; contents of
; memory location 21h


使用伪指令

使用 a 命令提供两个常用的伪指令：db 操作码，将字节值直接汇编到内存，dw 操作码，将字值直接汇编到内存。以下是两个伪指令的范例：

db 1,2,3,4,"THIS IS AN EXAMPLE"
db 'THIS IS A QUOTATION MARK:"'
db "THIS IS A QUOTATION MARK:'"
dw 1000,2000,3000,"BACH"


范例

a 命令支持所有形式的间接注册命令，如下例所示：

add bx,34[bp+2].[si-1]
pop [bp+di]
push [si] )

还支持所有操作码同义词，如下例所示：

loopz 100
loope 100
ja 200
jnbe 200

对于 8087 操作码，必须指定 wait 或 fwait 前缀，如下例所示：

fwait fadd st,st(3) ; this line assembles
; an fwait prefix


Debug:C（比较）


比较内存的两个部分。


c range address


参数

range

指定要比较的内存第一个区域的起始和结束地址，或起始地址和长度。有关有效的 range 值的信息，请单击“相关主题”列表中的“Debug 说明”。

address

指定要比较的第二个内存区域的起始地址。有关有效 address 值的信息，请单击“相关主题”列表中的“Debug 说明”。


说明

如果 range 和 address 内存区域相同，Debug 将不显示任何内容而直接返回到 Debug 提示符。如果有差异，Debug 将按如下格式显示：
address1 byte1 byte2 addess2

范例

以下命令具有相同效果：

c100,10f 300
c100l10 300

每个命令都对 100h 到 10Fh 的内存数据块与 300h 到 30Fh 的内存数据块进行比较。

Debug 响应前面的命令并显示如下信息（假定 DS = 197F）：

197F:0100 4D E4 197F:0300
197F:0101 67 99 197F:0301
197F:0102 A3 27 197F:0302
197F:0103 35 F3 197F:0303
197F:0104 97 BD 197F:0304
197F:0105 04 35 197F:0305
197F:0107 76 71 197F:0307
197F:0108 E6 11 197F:0308
197F:0109 19 2C 197F:0309
197F:010A 80 0A 197F:030A
197F:010B 36 7F 197F:030B
197F:010C BE 22 197F:030C
197F:010D 83 93 197F:030D
197F:010E 49 77 197F:030E
197F:010F 4F 8A 197F:030F

注意列表中缺少地址 197F:0106 和 197F:0306。这表明那些地址中的值是相同的。


Debug:D（转储）


显示一定范围内存地址的内容。


d [range]


参数

range

指定要显示其内容的内存区域的起始和结束地址，或起始地址和长度。有关有效的 range 值的信息，请单击“相关主题”列表中的“Debug 说明”。如果不指定 range，Debug 程序将从以前 d 命令中所指定的地址范围的末尾开始显示 128 个字节的内容。

有关显示寄存器内容的信息，请单击“相关主题”列表中的 Debug R（寄存器）。


说明
当使用 d 命令时，Debug 以两个部分显示内存内容：十六进制部分（每个字节的值都用十六进制格式表示）和 ASCII 码部分（每个字节的值都用 ASCII 码字符表示)。每个非打印字符在显示的 ASCII 部分由句号 (.) 表示。每个显示行显示 16 字节的内容，第 8 字节和第 9 字节之间有一个连字符。每个显示行从 16 字节的边界上开始。

范例
假定键入以下命令：
dcs:100 10f
Debug 按以下格式显示范围中的内容：
04BA:0100 54 4F 4D 00 53 41 57 59-45 52 00 00 00 00 00 00 TOM.SAWYER......
如果在没有参数的情况下键入 d 命令，Debug 按以前范例中所描述的内容来编排显示格式。显示的每行以比前一行的地址大 16 个字节（如果是显示 40 列的屏幕，则为 8 个字节）的地址开头。
对于后面键入的每个不带参数的 d 命令，Debug 将紧接在最后显示的命令后立即显示字节内容。
如果键入以下命令，Debug 将从 CS:100 开始显示 20h 个字节的内容：
dcs:100 l 20
如果键入以下命令，Debug 将显示范围从 CS 段的 100h 到 115h 中所有字节的内容：
dcs:100 115

Debug:E（键入）

将数据输入到内存中指定的地址。
可以按十六进制或 ASCII 格式键入数据。以前存储在指定位置的任何数据全部丢失。

e address [list]

参数
address
指定输入数据的第一个内存位置。
list
指定要输入到内存的连续字节中的数据。
有关集成记忆码的信息，请单击“相关主题”列表中的 Debug A（汇编）。
有关显示内存部分内容的信息，请单击“相关主题”列表中的 Debug D （转储）。

说明

使用 address 参数

如果在没有指定可选的 list 参数的值情况下指定 address 的值，Debug 将显示地址和内容，在下一行重复地址，并等待您的输入。此时，您可以执行下列操作之一：

替换字节值。为此，请在当前值后键入新值。如果您键入的值不是有效的十六进制值，或该值包含两个以上的数字，则 Debug 不会回显无效或额外的字符。
进入下一个字节。为此，请按 SPACEBAR（空格键）。要更改该字节中的值，请在当前值后键入新值。如果按 SPACEBAR（空格键）时，移动超过了 8 位界限，Debug 程序将显示新的一行并在行首显示新地址。
返回到前一个字节。为此，请按 HYPHEN 键 (-)。可以反复按 HYPHEN 键 (-) 向后移动超过多个字节。在按 HYPHEN 时，Debug 开始新行并显示当前地址和字节值。
停止执行 e 命令。为此，请按 ENTER 键。在任何字节位置都可以按 ENTER。
使用 list 参数

如果指定 list 参数的值，随后的 e 命令将使用列表中的值替换现有的字节值。如果发生错误，将不更改任何字节值。

List 值可以是十六进制字节或字符串。使用空格、逗号或制表符来分隔值。必须将字符串包括在单或双引号中。

范例

假定键入以下命令：

ecs:100

Debug 按下面的格式显示第一个字节的内容：

04BA:0100 EB.

要将该值更改为 41，请在插入点键入 41，如下所示：

04BA:0100 EB.41_

可以用一个 e 命令键入连续的字节值。在键入新值后按 SPACEBAR（空格键），而不是按 ENTER 键。Debug 显示下一个值。在此范例中，如果按三次 SPACEBAR（空格键），Debug 将显示下面的值：

04BA:0100 EB.41 10. 00. BC._

要将十六进制值 BC 更改为 42，请在插入点键入 42，如下所示：

04BA:0100 EB.41 10. 00. BC.42_

假定决定值 10 应该是 6F。要纠正该值，请按 HYPHEN 键两次以返回到地址 0101（值 10）。Debug 显示以下内容：

04BA:0100 EB.41 10. 00. BC.42-
04BA:0102 00.-
04BA:0101 10._

在插入点键入 6f 更改值，如下所示：

04BA:0101 10.6f_

按 ENTER 停止 e 命令并返回到 Debug 提示符下。

以下是字符串项的范例：

eds:100 "This is the text example"

该字符串将从 DS:100 开始填充 24 个字节

Debug:F（填充）

使用指定的值填充指定内存区域中的地址。

可以指定十六进制或 ASCII 格式表示的数据。任何以前存储在指定位置的数据将会丢失。


f range list


参数

range

指定要填充内存区域的起始和结束地址，或起始地址和长度。关于有效的 range 值的信息，请单击“相关主题”列表中的“Debug 说明”。

list

指定要输入的数据。List 可以由十六进制数或引号包括起来的字符串组成。


说明

使用 range 参数

如果 range 包含的字节数比 list 中的数值大，Debug 将在 list 中反复指派值，直到 range 中的所有字节全部填充。

如果在 range 中的任何内存损坏或不存在，Debug 将显示错误消息并停止 f 命令。


使用 list 参数

如果 list 包含的数值多于 range 中的字节数，Debug 将忽略 list 中额外的值。


范例

假定键入以下命令：

f04ba:100l100 42 45 52 54 41

作为响应，Debug 使用指定的值填充从 04BA:100 到 04BA:1FF 的内存位置。Debug 重复这五个值直到 100h 个字节全部填满为止。


Debug:G（转向）


运行当前在内存中的程序。


g [=address] [breakpoints]


参数

=address

指定当前在内存中要开始执行的程序地址。如果不指定 address，Windows 2000 将从 CS:IP 寄存器中的当前地址开始执行程序。

breakpoints

指定可以设置为 g 命令的部分的 1 到 10 个临时断点。

有关执行循环、重复的字符串指令、软件中断或子程序的信息，请单击“相关主题”列表中的 Debug P（执行）。

有关执行指令的信息，请单击“相关主题”列表中的 Debug T（跟踪）。

Debug:H（十六进制）

对指定的两个参数执行十六进制运算。


h value1 value2


参数

value1

代表从 0 到 FFFFh 范围内的任何十六进制数字。

value2

代表从 0 到 FFFFh 范围内第二个十六进制数字。


说明

Debug 首先将指定的两个参数相加，然后从第一个参数中减去第二个参数。这些计算的结果显示在一行中：先计算和，然后计算差。


范例

假定键入以下命令：

h19f 10a

Debug 执行运算并显示以下结果。
02A9 0095

Debug:I（输入）


从指定的端口读取并显示一个字节值。

i port

参数

port

按地址指定输入端口。地址可以是 16 位的值。

有关将字节值发送到输出端口的信息，请单击“相关主题”列表中的 Debug O（输出）。


范例

假定键入以下命令：

i2f8

同时假定端口的字节值是 42h。Debug 读取该字节，并将其值显示如下：
42


Debug:L（加载）

将某个文件或特定磁盘扇区的内容加载到内存。

要从磁盘文件加载 BX:CX 寄存器中指定的字节数内容，请使用以下语法：

l [address]

要略过 Windows 2000 文件系统并直接加载特定的扇区，请使用以下语法：

l address drive start number


参数

address

指定要在其中加载文件或扇区内容的内存位置。如果不指定 address，Debug 将使用 CS 寄存器中的当前地址。

drive

指定包含读取指定扇区的磁盘的驱动器。该值是数值型：0 = A, 1 = B, 2 = C 等。

start

指定要加载其内容的第一个扇区的十六进制数。

number

指定要加载其内容的连续扇区的十六进制数。只有要加载特定扇区的内容而不是加载 debug 命令行或最近的 Debug n（名称）命令中指定的文件时，才能使用 drive、start 和 number 参数。

有关指定用于 l 命令的文件的信息，请单击“相关主题”列表中的 Debug n（名称）。

有关写入调试到磁盘的文件的信息，请单击“相关主题”列表中的 Debug w（写入）。


注意

使用不带参数的 l 命令

当使用不带参数的 l 命令时，在 debug 命令行上指定的文件将加载到内存中，从地址 CS:100 开始。Debug 同时将 BX 和 CX 寄存器设置为加载的字节数。如果不在 debug 命令行指定文件，所装入的文件将是最近使用 n 命令经常指定的文件。


使用具有 address 参数的 1 命令

如果使用带 address 参数的 l 命令，Debug 将从内存位置 address 开始加载文件或指定扇区的内容。


使用带全部参数的 l 命令

如果使用带所有参数的 l 命令，Debug 将加载指定磁盘扇区的内容而不是加载文件。


加载特定扇区的内容

指定范围内的每个扇区均从 drive 读取。Debug 从 start 开始加载，直到在 number 中指定的扇区数中的内容全部被加载。


加载 .exe 文件

Debug 忽略 .exe 文件的地址 address 参数。如果指定 .exe 文件，Debug 将文件重新定位到 .exe 文件的标题中指定的加载地址。在 .exe 文件被加载到内存前，标题自身从 .exe 文件脱离，因此磁盘上的 .exe 文件大小与内存中的不同。如果要检查整个 .exe 文件，请使用不同的扩展名重命名文件。


打开十六进制文件

Debug 将具有 .hex 扩展名的文件认为十六进制格式文件。键入不带参数的 l 命令，可以加载从十六进制文件中指定的地址处开始的十六进制文件。如果键入的 l 命令包含 address 参数，Debug 将把指定的地址加到在十六进制文件中找到的地址上，以确定起始地址。


范例

假定启动 Debug 并键入以下命令：

nfile.com

现在可以键入 l 命令以加载 File.com。Debug 将加载文件并显示 Debug 提示符。

假定需要从驱动器 C 将起始逻辑扇区为 15 (0Fh) 的 109 (6Dh) 个扇区的内容加载到起始地址为 04BA:0100 的内存中。为此，请键入以下命令：
l04ba:100 2 0f 6d


Debug:M（移动）



将一个内存块中的内容复制到另一个内存块中。

m range address


参数

range

指定要复制内容的内存区域的起始和结束地址，或起始地址和长度。

address

指定要将 range 内容复制到该位置的起始地址。

说明

复制操作对现有数据的影响

如果新数据没有写入正在被复制的数据块中的地址，则源数据将保持不变。但是，如果目标块已经包含数据(就象它在覆盖副本操作中一样)，则将改写该数据。（覆盖复制操作是指那些目标数据块部分内容覆盖原数据块部分内容的操作。）


执行覆盖复制操作

m 命令执行目标地址的覆盖复制操作，而不丢失数据。将改写的地址内容首先复制。因此，如果将较高位地址的数据复制到较低位地址，则复制操作从原块的最低位地址开始并向最高位地址进行。反之，如果要将数据从低地址复制到高地址，复制操作从原块的最高地址开始，向最低地址进行。


范例

假定键入以下命令：

mcs:100 110 cs:500
Debug 首先将 CS:110 地址中的内容复制到地址 CS:510 中，然后将 CS:10F 地址中的内容复制到 CS:50F 中，如此操作直至将 CS:100 地址中的内容复制到地址 CS:500 中。要查看结果，请使用 Debug d（转储）命令，并使用 m 命令指定目标地址

Debug:N（名称）



指定 Debug l（加载）或 w（写入）命令的可执行文件的名称，或者指定正在调试的可执行文件的参数。


n [drive:][path] filename


要指定测试的可执行文件的参数，请使用以下语法：

n file-parameters


参数

如果在没有参数的情况下使用，则 n 命令清除当前规范。
[drive:][path] filename

指定要测试的可执行文件的位置和名称。

file-parameters

为正在测试的可执行文件指定参数和开关。

有关将文件或指定磁盘扇区的内容加载到内存中的信息，请单击“相关主题”列表中的 Debug L（加载）。

有关写入调试到磁盘的文件的信息，请单击“相关主题”列表中的 Debug W（写入）。


说明

n 命令的两个用途

可以按两种方式使用 n 命令。首先，您可以使用它以指定后面的 l（加载）或 w（写入）命令所使用的文件。如果在没有命名所调试文件的情况下启动 Debug，必须在使用 l 命令加载文件之前使用命令 nfilename。在 CS:5C 为文件控制块 (FCB) 正确编排文件名的格式。其次，可以使用 n 命令指定被调试文件的命令行参数和开关。


内存区域

以下四个内存区域都会受到 n 命令的影响：

内存位置
内容

CS:5C
文件 1 的文件控制数据块 (FCB)

CS:6C
文件 2 的文件控制数据块 (FCB)

CS:80
n 命令行的长度（以字符表示）

CS:81
n 命令行字符的开头


为 n 命令指定的第一个文件名被放在 CS:5C 的 FCB 中。如果指定第二个文件名，此名称将放置到 CS:6C 的 FCB 中。n 命令行上键入的字符数（除第一个字符之外，n）存储在位置 CS:80。n 命令行上的实际字符（再次，除了字母 n 之外）存储在以 CS:81 开头的位置。注意这些字符可以是在 Windows 2000 命令提示符下键入的命令中有效的任何开关和分隔符。


范例

假定已经启动 Debug，并加载了正在调试的程序 Prog.com。接着您决定为 Prog.com 指定两个参数并运行此程序。以下是此范例的命令序列：

debug prog.com
nparam1 param2
g

在这种情况下，Debug g（转向）命令会运行该程序，就好像您已在 Windows 2000 命令提示符后键入了如下命令：

prog param1 param2

所以，测试和调试反映 Prog.com 通常的运行时间环境。

在下面的命令序列中，第一个 n 命令将 File1.exe 指定为后接的 l（加载）命令的文件，该命令将 File1.exe 加载到内存。第二个 n 命令指定 File1.exe 将使用的参数。最后，g 命令将运行 File1.exe 文件，就好像您在 Windows 2000 命令行中键入了 File1 File2.dat File2.dat 一样。

nfile1.exe
l
nfile2.dat file3.dat
g

注意
不要在 n 命令的第二种形式后使用 l 命令。还要注意，如果现在使用 w（写入）命令，Windows 2000 将使用名称 File2.dat 保存正在调试的文件 File1.exe。为避免出现此结果，应该总是在 l 或 w 命令之前立即使用 n 命令的第一种形式。

Debug:O（输出）



将字节值发送到输出端口。


o port byte-value


参数

port

通过地址指定输出端口。端口地址可以是 16 位值。

byte-value

指定要指向 port 的字节值。

有关从输入端口读取字节值的信息，请单击“相关主题”列表中的 Debug I（输入）。

范例

要将字节值 4Fh 发送到地址为 2F8h 的输出端口，请键入以下命令：
o2f8 4f

Debug:P（执行）



执行循环、重复的字符串指令、软件中断或子例程；或通过任何其他指令跟踪。


p [= address] [number]


参数

=address

指定第一个要执行指令的位置。如果不指定地址，则默认地址是在 CS:IP 寄存器中指定的当前地址。

number

指定在将控制返回给 Debug 之前要执行的指令数。默认值为 1。

有关运行当前在内存中程序的信息，请单击“相关主题”列表中的 Debug G（转向）。

有关执行指令的信息，请单击“相关主题”列表中的 Debug T（跟踪）。


说明
控制传送到要测试的程序

当 p 命令将控制从 Debug 传送到要测试的程序时，该程序不间断运行，直到循环、重复字符串指令、软件中断或者完成了指定地址的子例程为止，或者直到执行了指定数量的机器指令为止。控制返回到 Debug。

地址参数的限制

如果 address 参数没有指定段，Debug 将使用被测试程序的 CS 寄存器。如果省略 address，程序将从 CS:IP 寄存器所指定的地址开始执行。必须在 address 参数之前使用等号 (=) 以便将它与 number 参数区分。如果在指定地址处的指令不是循环、重复的字符串指令、软件中断或子例程，则 p 命令与 Debug t（跟踪）命令的作用相同。

使用 p 命令显示的邮件

当 p 执行完一段说明后，Debug 显示出程序的寄存器内容、标志的状态以及下一段将要被执行的指令的解码形式。


警告

不能使用 p 命令跟踪只读内存 (ROM)。

范例

假定正在测试的程序在地址 CS:143F 处包含一个 call 指令。要运行 call 目标位置的子程序然后将控制返回到 Debug，请键入以下命令：

p=143f

Debug 按以下格式显示结果：
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=2246 ES=2246 SS=2246 CS=2246 IP=1443 NV UP EI PL NZ AC PO NC
2246:1442 7505 JNZ 144A

Debug:Q（退出）



停止 Debug 会话，不保存当前测试的文件。

当您键入 q 以后，控制返回到 Windows 2000 的命令提示符。


q


参数

该命令不带参数。
有关保存文件的信息，请单击“相关主题”列表中的 Debug W（写入）。

Debug:R（寄存器）


显示或改变一个或多个 CPU 寄存器的内容。


r [register-name]


参数

无

如果在没有参数的情况下使用，则 r 命令显示所有寄存器的内容以及寄存器存储区域中的标志。

register-name

指定要显示其内容的寄存器名。

有关显示内存部分内容的信息，请单击“相关主题”列表中的 Debug D（转储）。

有关反汇编字节的信息，请单击“相关主题”列表中的 Debug U（反汇编）。


说明

使用 r 命令

如果指定了寄存器名称，Windows 2000 将显示以十六进制标记表示的寄存器的 16 位值，并将冒号显示为提示符。如果要更改包含在寄存器中的值，除非键入新值并按 ENTER 键；否则，请按 ENTER 键返回 Debug 提示符。

有效寄存器名

以下是 register-name 的有效值：ax、bx、cx、dx、sp、bp、si、di、ds、es、ss、cs、ip、pc 及 f。ip 和 pc 都引用指令指针。

如果指定寄存器名称，而不是从前面的列表中指定，Windows 2000 将显示以下消息：

br error

使用 f 字符而不是寄存器名

如果键入 f 字符代替寄存器名，Debug 将每个标记的当前设置显示为两字母代码，然后显示 Debug 提示符。要更改标志的设置，请从下表中键入适当的两字母代码：

标志名
设置
清除

溢出
ov
nv

方向
dn（减）
up（增）

中断
ei（启用）
di（禁用）

正负
ng（负）
pl（正）

零
zr
nz

辅助进位
ac
na

奇偶校验
pe（偶校验）
po（奇校验）

进位
cy
nc


可以按任何顺序键入新的标志值。不需要在这些值之间留出空格。要停止 r 命令，请按 ENTER 键。任何没有指定新值的标志保持不变。

用 r 命令显示的邮件

如果为标记指定了多个值，Debug 将显示以下消息：

df error

如果指定没有在前面的表中列出的标志代码，Debug 将显示以下消息：

bf error

在这两种情况下，Debug 将忽略所有在无效项目之后指定的设置。

Debug 的默认设置

在启动 Debug 时，会将段寄存器设置到空闲内存的低端，指令指针设置为 0100h，清除所有标志，并且将其余寄存器设置为零，除了被设置为 FFEEh 的 sp 之外。

Debug:R


范例

要查看所有寄存器的内容、所有标记的状态和当前位置的指令解码表，请键入以下命令：

r

如果当前位置是 CS:11A，显示外观将类似于以下内容：

AX=0E00 BX=00FF CX=0007 DX=01FF SP=039D BP=0000 SI=005C DI=0000
DS=04BA ES=04BA SS=04BA CS=O4BA IP=011A NV UP DI NG NZ AC PE NC
04BA:011A CD21 INT 21

要只查看标志的状态，请键入以下命令：

rf

Debug 按以下格式显示信息：

NV UP DI NG NZ AC PE NC - _

现在，您可以按任意顺序键入一个或多个有效的标志值，其中可以有或没有空格，如下所示：

nv up di ng nz ac pe nc - pleicy

Debug 结束 r 命令并显示 Debug 提示符。要查看更改，请键入 r 或 rf 命令。Debug 将显示以下内容：

NV UP EI PL NZ AC PE CY - _
按 ENTER 返回到 Debug 提示符。

Debug:S（搜索）



在某个地址范围搜索一个或多个字节值的模式。


s range list


参数

range

指定要搜索范围的开始和结束地址。有关 range 参数有效值的信息，请单击“相关主题”列表中的 Debug。

list

指定一个或多个字节值的模式，或要搜索的字符串。用空格或逗号分隔每个字节值和下一个字节值。将字符串值包括在引号中。


说明

如果 list 参数包含多个字节值，Debug 将只显示出现字节值的第一个地址。如果 list 只包含一个字节值，Debug 将显示指定范围内出现该值的所有地址。


范例

假定需要查找包含值 41 并且范围从 CS:100 到 CS:110 的所有地址。为此，请键入以下命令：

scs:100 110 41

Debug 按以下格式显示结果：

04BA:0104
04BA:010D
-

以下命令在 CS:100 到 CS:1A0 的范围内搜索字符串“Ph”。
scs:100 1a0 "Ph"

Debug:U（反汇编）


反汇编字节并显示相应的原语句，其中包括地址和字节值。反汇编代码看起来象已汇编文件的列表。


u [range]


参数

无

如果在没有参数的情况下使用，则 u 命令分解 20h 字节（默认值），从前面 u 命令所显示地址后的第一个地址开始。

range

指定要反汇编代码的起始地址和结束地址，或起始地址和长度。有关 range 参数有效值的信息，请单击“相关主题”列表中的 Debug。

有关集成记忆码的信息，请单击“相关主题”列表中的 Debug A（汇编）。

有关显示内存部分内容的信息，请单击“相关主题”列表中的 Debug D（转储）。

范例



要反汇编 16 (10h) 字节，从地址 04BA:0100 开始，请键入以下命令：

u04ba:100l10

Debug 按以下格式显示结果：

04BA:0100 206472 AND [SI+72],AH
04BA:0103 69 DB 69
04BA:0104 7665 JBE 016B
04BA:0106 207370 AND [BP+DI+70],DH
04BA:0109 65 DB 65
04BA:010A 63 DB 63
04BA:010B 69 DB 69
04BA:010C 66 DB 66
04BA:010D 69 DB 69
04BA:010E 63 DB 63
04BA:010F 61 DB 61

如果只显示从 04BA:0100 到 04BA:0108 特定地址的信息，请键入以下命令：

u04ba:0100 0108

Debug 显示以下内容：

04BA:0100 206472 AND [SI+72],AH
04BA:0103 69 DB 69
04BA:0104 7665 JBE 016B
04BA:0106 207370 AND [BP+DI+70],DH

Debug:W（写入）



将文件或特定分区写入磁盘。

要将在 BX:CX 寄存器中指定字节数的内容写入磁盘文件，请使用以下语法：


w [address]


要略过 Windows 2000 文件系统并直接写入特定的扇区，请使用以下语法：

w address drive start number


参数

address

指定要写到磁盘文件的文件或部分文件的起始内存地址。如果不指定 address，Debug 程序将从 CS:100 开始。关于 address 参数有效值的信息，请在“相关主题”列表中单击 Debug。

drive

指定包含目标盘的驱动器。该值是数值型：0 = A, 1 = B, 2 = C,等等。

start

指定要写入第一个扇区的十六进制数。

number

指定要写入的扇区数。

有关指定用于 w 命令的文件的信息，请单击“相关主题”列表中的 Debug N（名称）。

有关将文件或文件扇区内容加载到内存中的信息，请单击“相关主题”列表中的 Debug L（加载）。

说明

必须在启动 Debug 时或者在最近的 Debug n（名称）命令中指定磁盘文件的名字。这两种方法都可以将地址 CS:5C 处文件控制块的文件名正确地编排格式。


在使用不带参数的 w 命令之前重新设置 BX:CX

如果使用了 Debug g（转向）、t（跟踪）、p（执行）或 r（寄存器）命令，必须在使用无参数的 w 命令之前，将 BX:CX 寄存器复位。

将修改后的文件写入磁盘

如果修改文件但不更改文件名、长度或起始地址，Debug 仍然可以正确地将文件写入源磁盘位置。

w 命令的限制

不能用该命令写入 .exe 或 .hex 文件。

警告

因为略过 Windows 2000 文件句柄，所以写入特定的分区非常危险。如果键入错误的值，则磁盘文件结构很容易被损坏。

范例

假定要将起始地址为 CS:100 的内存内容写入到驱动器 B 的磁盘中。需要将数据从磁盘的逻辑扇区号 37h 开始并持续 2Bh 个扇区。为此，键入以下命令：

wcs:100 1 37 2b

当写操作完成时，Debug 再次显示 Debug 提示符。

Debug:XA（分配扩展内存）

分配扩展内存的指定页面数。

要使用扩展内存，必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xa [count]


参数

count

指定要分配的扩展内存的 16KB 页数。

有关使用扩展内存的其他 Debug 命令的信息，请单击“相关主题”列表中的 XD（释放扩展内存）、XM（映射扩展内存页）或 XS（显示扩展内存状态）。

说明

如果指定的页面数可用，则 Debug 将显示消息，此消息表明所创建的句柄的十六进制数；否则，Debug 将显示错误消息。



Debug:XA

范例

要分配扩展内存的 8 个页面，请键入以下命令：

xa8

如果命令成功，Debug 将显示类似的以下消息：
Handle created=0003

Debug:XD（释放扩展内存）


释放指向扩展内存的句柄。

要使用扩展内存，必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xd [handle]


参数

handle

指定要释放的句柄。

有关使用扩展内存的其他 Debug 命令的信息，请单击“相关主题”列表中 XA（分配扩展内存）、XM（映射扩展内存页） 或 XS（显示扩展内存状态）。

范例

要释放句柄 0003，请键入以下命令：

xd 0003

如果命令成功，Debug 将显示下列消息：
Hdle 0003 deallocated

Debug:XM（映射扩展内存页）


将属于指定句柄的扩展内存逻辑页映射到扩展内存的物理页。

要使用扩展内存，必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xm [lpage] [ppage] [handle]


参数

lpage

指定要映射到物理页 ppage 的扩展内存的逻辑页面号。

ppage

指定将 lpage 映射到的物理页面号。

handle

指定句柄。

有关使用扩展内存的其他 Debug 命令的信息，请单击“相关主题”列表中的 XA（分配扩展内存）、XD（释放扩展内存）或 XS（显示扩展内存）。


范例

要将句柄 0003 的逻辑页 5 映射到物理页 2，请键入以下命令：

xm 5 2 0003

如果命令成功，Debug 将显示下列消息：

Logical page 05 mapped to physical page 02

Debug:XS（显示扩展内存状态）


显示有关扩展内存状态的信息。

要使用扩展内存，必须安装符合 4.0 版的 Lotus/Intel/Microsoft 扩展内存规范 (LIM EMS) 的扩展内存设备驱动程序。


xs


参数

该命令不带参数。

有关使用扩展内存的其他 Debug 命令的信息，请单击“相关主题”列表中的 XA（分配扩展内存）、XD（释放扩展内存）或 XM（映射扩展内存页）。


说明

Debug 显示的信息有如下格式：

Handle xx has xx pages allocated
Physical page xx = Frame segment xx
xx of a total xx EMS pages have been allocated
xx of a total xx EMS handles have been allocated


范例

要显示扩展内存信息，请键入以下命令：

xs

Debug 显示与以下类似的信息：

Handle 0000 has 0000 pages allocated
Handle 0001 has 0002 pages allocated
Physical page 00 = Frame segment C000
Physical page 01 = Frame segment C400
Physical page 02 = Frame segment C800
Physical page 03 = Frame segment CC00
2 of a total 80 EMS pages have been allocated
2 of a total FF EMS handles have been allocated
　

汇编教程：	　
汇编语言超浓缩教程

作者：
作者网站：
文章源自：计算机文摘主页
收藏日期：2003-10-03
　
　
   “ 哎哟，哥们儿，还捣鼓汇编呢？那东西没用，兄弟用VB"钓"一个API就够你忙活个十天半月的，还不一定搞出来。”此君之言倒也不虚，那吾等还有无必要研他一究呢？（废话，当然有啦！要不然你写这篇文章干嘛。）别急，别急，让我把这个中原委慢慢道来：一、所有电脑语言写出的程序运行时在内存中都以机器码方式存储，机器码可以被比较准确的翻译成汇编语言，这是因为汇编语言兼容性最好，故几乎所有跟踪、调试工具（包括WIN95/98下）都是以汇编示人的，如果阁下对CRACK颇感兴趣……；二、汇编直接与硬件打交道，如果你想搞通程序在执行时在电脑中的来龙去脉，也就是搞清电脑每个组成部分究竟在干什么、究竟怎么干？一个真正的硬件发烧友，不懂这些可不行。三、如今玩DOS的多是“高手”，如能像吾一样混入（我不是高手）“高手”内部，不仅可以从“高手”朋友那儿套些黑客级“机密”，还可以自诩“高手”尽情享受强烈的虚荣感--#$%& “醒醒!”
　　对初学者而言，汇编的许多命令太复杂，往往学习很长时间也写不出一个漂漂亮亮的程序，以致妨碍了我们学习汇编的兴趣，不少人就此放弃。所以我个人看法学汇编，不一定要写程序，写程序确实不是汇编的强项，大家不妨玩玩DEBUG，有时CRACK出一个小软件比完成一个程序更有成就感（就像学电脑先玩游戏一样）。某些高深的指令事实上只对有经验的汇编程序员有用，对我们而言，太过高深了。为了使学习汇编语言有个好的开始，你必须要先排除那些华丽复杂的命令，将注意力集中在最重要的几个指令上（CMP LOOP MOV JNZ……）。但是想在啰里吧嗦的教科书中完成上述目标，谈何容易，所以本人整理了这篇超浓缩（用WINZIP、WINRAR…依次压迫，嘿嘿！）教程。大言不惭的说，看通本文，你完全可以“不经意”间在前辈或是后生卖弄一下DEBUG，很有成就感的，试试看！那么――这个接下来呢？―― Here we go！（阅读时看不懂不要紧，下文必有分解）

　　因为汇编是通过CPU和内存跟硬件对话的，所以我们不得不先了解一下CPU和内存：（关于数的进制问题在此不提）

　　ＣＰＵ是可以执行电脑所有算术╱逻辑运算与基本 I/O 控制功能的一块芯片。一种汇编语言只能用于特定的CPU。也就是说，不同的CPU其汇编语言的指令语法亦不相同。个人电脑由1981年推出至今，其CPU发展过程为：8086→80286→80386→80486→PENTIUM →……，还有AMD、CYRIX等旁支。后面兼容前面CPU的功能，只不过多了些指令（如多能奔腾的MMX指令集）、增大了寄存器（如386的32位EAX）、增多了寄存器（如486的FS）。为确保汇编程序可以适用于各种机型，所以推荐使用8086汇编语言，其兼容性最佳。本文所提均为8086汇编语言。寄存器（Register）是CPU内部的元件，所以在寄存器之间的数据传送非常快。用途：1.可将寄存器内的数据执行算术及逻辑运算。2.存于寄存器内的地址可用来指向内存的某个位置，即寻址。3.可以用来读写数据到电脑的周边设备。8086 有8个8位数据寄存器，这些8位寄存器可分别组成16位寄存器：ＡＨ&ＡＬ＝ＡＸ：累加寄存器，常用于运算；ＢＨ&ＢＬ＝ＢＸ：基址寄存器，常用于地址索引；ＣＨ&ＣＬ＝ＣＸ：计数寄存器，常用于计数；ＤＨ&ＤＬ＝ＤＸ：数据寄存器，常用于数据传递。为了运用所有的内存空间，8086设定了四个段寄存器，专门用来保存段地址：ＣＳ（Code Segment）：代码段寄存器；ＤＳ（Data Segment）：数据段寄存器；ＳＳ（Stack Segment）：堆栈段寄存器；ＥＳ（Extra Segment）：附加段寄存器。当一个程序要执行时，就要决定程序代码、数据和堆栈各要用到内存的哪些位置，通过设定段寄存器 CS，DS，SS 来指向这些起始位置。通常是将DS固定，而根据需要修改CS。所以，程序可以在可寻址空间小于64K的情况下被写成任意大小。 所以，程序和其数据组合起来的大小，限制在DS 所指的64K内，这就是COM文件不得大于64K的原因。8086以内存做为战场，用寄存器做为军事基地，以加速工作。除了前面所提的寄存器外，还有一些特殊功能的寄存器：IP（Intruction Pointer）：指令指针寄存器，与CS配合使用，可跟踪程序的执行过程；SP（Stack Pointer）：堆栈指针，与SS配合使用，可指向目前的堆栈位置。BP（Base Pointer）：基址指针寄存器，可用作SS的一个相对基址位置；SI（Source Index）：源变址寄存器可用来存放相对于DS段之源变址指针；DI（Destination Index）：目的变址寄存器，可用来存放相对于 ES 段之目的变址指针。还有一个标志寄存器FR（Flag Register）,有九个有意义的标志，将在下文用到时详细说明。

　　内存是电脑运作中的关键部分，也是电脑在工作中储存信息的地方。内存组织有许多可存放数值的储存位置，叫“地址”。8086地址总线有20位，所以CPU拥有达1M的寻址空间，这也是DOS的有效控制范围，而8086能做的运算仅限于处理16位数据，即只有0到64K，所以，必须用分段寻址才能控制整个内存地址。完整的20位地址可分成两部份：1.段基址(Segment)：16位二进制数后面加上四个二进制０，即一个16进制０，变成20位二进制数，可设定1M中任何一个64K段，通常记做16位二进制数；2.偏移量(Offset)：直接使用16位二进制数，指向段基址中的任何一个地址。如：2222（段基址）:3333（偏移量），其实际的20位地址值为：25553。除了上述营养要充分吸收外，你还要知道什么是DOS、BIOS功能调用，简单的说，功能调用类似于WIN95 API，相当于子程序。汇编写程序已经够要命了，如果不用MS、IBM的子程序，这日子真是没法过了（关于功能调用详见《电脑爱好者》98年11期）。

　　编写汇编语言有两种主要的方法：1.使用MASM或TASM等编译器；2.使用除错程序DEBUG.COM。DEBUG其实并不能算是一个编译器，它的主要用途在于除错，即修正汇编程序中的错误。不过，也可以用来写短的汇编程序，尤其对初学者而言，DEBUG 更是最佳的入门工具。因为DEBUG操作容易：只要键入DEBUG回车，A回车即可进行汇编，过程简单，而使用编译器时，必须用到文本编辑器、编译器本身、LINK以及EXE2BIN等程序，其中每一个程序都必须用到一系列相当复杂的命令才能工作，而且用编译器处理源程序，必须加入许多与指令语句无关的指示性语句，以供编译器识别，使用 DEBUG 可以避免一开始就碰到许多难以理解的程序行。DEBUG 除了能够汇编程序之外，还可用来检查和修改内存位置、载入储存和执行程序、以及检查和修改寄存器，换句话说，DEBUG是为了让我们接触硬件而设计的。（8086常用指令用法将在每个汇编程序中讲解，限于篇幅，不可能将所有指令列出）。

　　DEBUG的的A命令可以汇编出简单的COM文件，所以DEBUG编写的程序一定要由地址 100h（COM文件要求）开始才合法。FOLLOW ME，SETP BY SETP（步步回车）：

　　输入 A100 ； 从DS：100开始汇编
　　2.输入 MOV DL,1 ； 将数值 01h 装入 DL 寄存器
　　3.输入 MOV AH,2 ； 将数值 02h 装入 DL 寄存器
　　4.输入 INT 21 ； 调用DOS 21号中断2号功能，用来逐个显示装入DL的字符
　　5.输入 INT 20 ； 调用DOS 20号中断，终止程序，将控制权交回给 DEBUG
　　6.请按 Enter 键
　　7.现在已将汇编语言程序放入内存中了，输入 G(运行)
　　8.出现结果：输出一个符号。
　　ㄖ ←输出结果其实不是它，因WORD97无法显示原结果，故找一赝品将就着。
　　Program terminated normally

　　我们可以用Ｕ命令将十六进制的机器码反汇编（Unassemble）成汇编指令。你将发现每一行右边的汇编指令就是被汇编成相应的机器码，而8086实际上就是以机器码来执行程序。
　　1.输入 U100,106
　　1FED:0100 B201 MOV DL,01
　　1FED:0102 B402 MOV AH,02
　　1FED:0104 CD21 INT 21
　　1FED:0106 CD20 INT 20
　　DEBUG可以用Ｒ命令来查看、改变寄存器内容。CS：IP寄存器，保存了将执行指令地址。
　　1.输入R
　　AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
　　DS=1FED ES=1FED SS=1FED CS=1FED IP=0100 NV UP EI PL NZ NA PO NC
　　1FED:0100 B201 MOV DL,01

　　当程序由DS：100开始执行，那么终止程序时，DEBUG会自动将IP内容重新设定为100。当你要将此程序做成一个独立的可执行文件，则可以用Ｎ命令对该程序命名。但一定要为COM文件，否则无法以DEBUG载入。
　　输入N SMILE.COM ；我们得告诉DEBUG程序长度：程序从100开始到106，故占用7
　　；字节。我们利用BX存放长度值高位部分，而以CX存放低位部分。
　　2.输入RBX ；查看 BX 寄存器的内容，本程序只有7个字节，故本步可省略
　　3.输入 RCX　 ；查看 CX 寄存器的内容
　　4.输入 7　 ；程序的字节数
　　5.输入 W ；用Ｗ命令将该程序写入（Write）磁盘中

　　修行至此，我们便可以真正接触8086汇编指令了。 当我们写汇编语言程序的时候，通常不会直接将机器码放入内存中，而是打入一串助记符号（Mnemonic Symbols），这些符号比十六进制机器码更容易记住，此之谓汇编指令。助记符号，告诉CPU应执行何种运算。 也就是说，助忆符号所构成的汇编语言是为人设计的，而机器语言是对PC设计的。

　　现在，我们再来剖析一个可以将所有ASCII码显示出来的程序。
　　1. 输入 DEBUG
　　2. 输入 A100
　　3．输入 MOV CX,0100 ；装入循环次数
　　MOV DL,00 ；装入第一个ASCII码，随后每次循环装入新码
　　MOV AH,02
　　INT 21
　　INC DL ；INC：递增指令，每次将数据寄存器 DL 内的数值加 1
　　LOOP 0105 ；LOOP：循环指令，每执行一次LOOP，CX值减1，并跳
　　；到循环的起始地址105，直到CX为0，循环停止
　　INT 20
　　4.输入 G即可显示所有ASCII码
　

　　当我们想任意显示字符串，如：UNDERSTAND？，则可以使用DOS21H号中断9H号功能。输入下行程序，存盘并执行看看：
　　1.输入 A100
　　 MOV DX,109 ；DS:DX ＝ 字符串的起始地址
　　 MOV AH,9 ；DOS的09h功能调用
　　INT 21 ；字符串输出
　　INT 20
　　DB 'UNDERSTAND？$'；定义字符串
　　在汇编语言中，有两种不同的指令：1.正规指令：如 MOV 等，是属于CPU的指令，用来告诉CPU在程序执行时应做些什么，所以它会以运算码（OP-code）的方式存入内存中；2.伪指令：如DB等，是属于DEBUG等编译器的指令，用来告诉编译器在编译时应做些什么。DB（Define Byte）指令用来告诉DEBUG 将单引号内的所有ASCII 码放入内存中。使用 9H 功能的字符串必须以$结尾。用Ｄ命令可用来查看DB伪指令将那些内容放入内存。
　　6.输入 D100
　　1975:0100 BA 09 01 B4 09 CD 21 CD-20 75 6E 64 65 72 73 74 ......!. underst
　　1975:0110 61 6E 64 24 8B 46 F8 89-45 04 8B 46 34 00 64 19 and$.F..E..F4.d.
　　1975:0120 89 45 02 33 C0 5E 5F C9-C3 00 C8 04 00 00 57 56 .E.3.^_.......WV
　　1975:0130 6B F8 0E 81 C7 FE 53 8B-DF 8B C2 E8 32 FE 0B C0 k.....S.....2...
　　1975:0140 74 05 33 C0 99 EB 17 8B-45 0C E8 D4 97 8B F0 89 t.3.....E.......
　　1975:0150 56 FE 0B D0 74 EC 8B 45-08 03 C6 8B 56 FE 5E 5F V...t..E....V.^_
　　1975:0160 C9 C3 C8 02 00 00 6B D8-0E 81 C3 FE 53 89 5E FE ......k.....S.^.
　　1975:0170 8B C2 E8 FB FD 0B C0 75-09 8B 5E FE 8B 47 0C E8 .......u..^..G..

　　现在，我们来剖析另一个程序：由键盘输入任意字符串，然后显示出来。db 20指示DEBUG保留20h个未用的内存空间供缓冲区使用。
　　输入A100
　　 MOV DX,0116 ；DS:DX ＝ 缓冲区地址，由DB伪指令确定缓冲区地址
　　MOV AH,0A ；0Ah 号功能调用
　　INT 21 ；键盘输入缓冲区
　　MOV DL,0A ；由于功能Ah在每个字符串最后加一个归位码（0Dh由 Enter
　　MOV AH,02 ；产生），使光标自动回到输入行的最前端，为了使新输出的
　　INT 21 ；字符串不会盖掉原来输入的字符串，所以利用功能2h加一
　　；个换行码(OAh)，使得光标移到下一行的的最前端。
　　MOV DX,0118 ；装入字符串的起始位置
　　MOV AH,09 ；9h功能遇到$符号才会停止输出，故字符串最后必须加上
　　INT 21 ；$，否则9h功能会继续将内存中的无用数据胡乱显示出来
　　INT 20
　　DB 20 ；定义缓冲区 
　　送你一句话：学汇编切忌心浮气燥。

　　客套话就不讲了。工欲善其事，必先利其器。与其说DEBUG 是编译器，倒不如说它是“直译器”，DEBUG的A命令只可将一行汇编指令转成机器语言，且立刻执行。真正编译器（MASM）的运作是利用文本编辑器（EDIT等）将汇编指令建成一个独立且附加名为.ASM的文本文件，称源程序。它是MASM 程序的输入部分。MASM将输入的ASM文件，编译成.OBJ文件，称为目标程序。OBJ文件仅包含有关程序各部份要载入何处及如何与其他程序合并的信息，无法直接载入内存执行。链结程序LINK则可将OBJ文件转换成可载入内存执行（EXEcute）的EXE文件。还可以用EXE2BIN，将符合条件的EXE文件转成COM文件（COM 文件不但占用的内存最少，而且运行速度最快）。
　　下面我们用MASM写一个与用DEBUG写的第一个程序功能一样的程序。
　　用EDIT编辑一个SMILE.ASM的源程序文件。
　　源程序 DEBUG 程序
　　prognam segment
　　assume cs:prognam
　　org 100h A100
　　mov dl,1 mov dl,1
　　mov ah,2 mov ah,2
　　int 21h int 21
　　int 20h int 20
　　prognam ends
　　end

　　比较一下：1.因为MASM会将所有的数值假设为十进制，而DEBUG则只使用十六进制，所以在源程序中，我们必须在有关数字后加上代表进制的字母，如H代表十六进制，D代表十进制。若是以字母开头的十六进制数字，还必须在字母前加个0，以表示它是数，如0AH。2.源程序增加五行叙述：prognam segment 与 prognam ends 是成对的，用来告诉 MASM 及LINK，此程序将放在一个称为PROGNAM(PROGram NAMe)的程序段内，其中段名（PROGNAM）可以任取，但其位置必须固定。assume cs:prognam 必须在程序的开头，用来告诉编译器此程序所在段的位置放在CS寄存器中。end用来告诉MASM，程序到此结束, ORG 100H作用相当于DEBUG的A100，从偏移量100开始汇编。COM 文件的所有源程序都必须包含这五行，且必须依相同的次序及位置出现，这点东西记下就行，千篇一律。接着，我们用MASM编译SMILE.ASM。
　　输入 MASM SMILE ←不用打入附加名.ASM。
　　Microsoft (R) Macro Assembler Version 5.10
　　Copyright (C) Microsoft Corp 1981, 1988. All rights reserved.
　　Object filename [SMILE.OBJ]: ←是否改动输出OBJ文件名，如不改就ENTER
　　Source listing [NUL.LST]: ← 是否需要列表文件（LST），不需要就ENTER
　　Cross-reference [NUL.CRF]: ←是否需要对照文件（CRF），不需要则ENTER
　　50162 + 403867 Bytes symbol space free
　　0 Warning Errors ←警告错误，表示编译器对某些语句不理解，通常是输入错误。
　　0 Severe Errors ←严重错误，会造成程序无法执行，通常是语法结构错误。

　　如果没有一个错误存在，即可生成OBJ文件。OBJ中包含的是编译后的二进制结果，它还无法被 DOS载入内存中加以执行，必须加以链结（Linking）。以LINK将OBJ文件（SMILE.OBJ）链结成 EXE 文件（SMILE.EXE）时，。
　　1.输入 LINK SMILE ←不用附加名OBJ
　　Microsoft (R) Overlay Linker Version 3.64
　　Copyright (C) Microsoft Corp 1981, 1988. All rights reserved.
　　Run File [SMILE.EXE]: ← 是否改动输出EXE文件名，如不改就ENTER
　　List File [NUL.MAP]: ← 是否需要列表文件（MAP），不需要则ENTER
　　Libraries [.LIB]: ←是否需要库文件，要就键入文件名，不要则ENTER
　　LINK : warning L4021: no stack segment← 由于COM文件不使用堆栈段，所以错误信息
　　←"no stack segment"并不影响程序正常执行

　　至此已经生成EXE文件，我们还须使用EXE2BIN 将EXE文件（SMILE.EXE），转换成COM文件（SMILE.COM）。输入EXE2BIN SMILE产生 BIN 文件（SMILE.BIN）。其实 BIN 文件与 COM 文件是完全相同的，但由于DOS只认COM、EXE及BAT文件，所以BIN文件无法被正确执行，改名或直接输入 EXE2BIN SMILE SMILE.COM即可。现在，磁盘上应该有 SMILE.COM 文件了，你只要在提示符号C：>下，直接输入文件名称 SMILE ，就可以执行这个程序了。

　　你是否觉得用编译器产生程序的方法，比 DEBUG 麻烦多了！以小程序而言，的确是如此，但对于较大的程序，你就会发现其优点了。我们再将ASCII程序以编译器方式再做一次，看看有无差异。首先，用EDIT.COM建立 ASCII.ASM 文件。
　　prognam segment ;定义段
　　assume cs:prognam ;把上面定义段的段基址放入 CS
　　mov cx,100h ; 装入循环次数
　　mov dl,0 ; 装入第一个ASCII码，随后每次循环装入新码
　　next: mov ah,2
　　 int 21h
　　 inc dl ;INC：递增指令，每次将数据寄存器 DL 内的数值加 1
　　loop next ; 循环指令，执行一次，CX减1，直到CX为0，循环停止
　　int 20h
　　 prognam ends ;段终止
　　end ;汇编终止
　　在汇编语言的源程序中，每一个程序行都包含三项元素：
　　　 start: mov dl,1 ；装入第一个ASCII码，随后每次循环装入新码
　　　 标识符 表达式 注解

　　在原始文件中加上注解可使程序更易理解，便于以后参考。每行注解以“；”与程序行分离。编译器对注解不予理会，注解的数据不会出现在OBJ、EXE或COM文件中。由于我们在写源程序时，并不知道每一程序行的地址，所以必须以符号名称来代表相对地址，称为“标识符”。我们通常在适当行的适当位置上，键入标识符。标识符（label）最长可达31 个字节，因此我们在程序中，尽量以简洁的文字做为标识符。现在，你可以将此ASCII.ASM 文件编译成 ASCII.COM 了。1.MASM ASCII，2.LINK ASCII，3.EXE2BIN ASCII ASCII.COM。

　　注意：当你以编译器汇编你设计的程序时，常会发生打字错误、标识符名称拼错、十六进制数少了ｈ、逻辑错误等。汇编老手常给新人的忠告是：最好料到自己所写的程序一定会有些错误（别人告诉我的）；如果第一次执行程序后，就得到期望的结果，你最好还是在检查一遍，因为它可能是错的。原则上，只要大体的逻辑架构正确，查找程序中错误的过程，与写程序本身相比甚至更有意思。写大程序时，最好能分成许多模块，如此可使程序本身的目的较单纯，易于撰写与查错，另外也可让程序中不同部份之间的界限较清楚，节省编译的时间。如果读程序有读不懂的地方最好用纸笔记下有关寄存器、内存等内容，在纸上慢慢比划，就豁然开朗了。 　　下面我们将写一个能从键盘取得一个十进制的数值，并将其转换成十六进制数值而显示于屏幕上的“大程序”。前言：要让8086执行这样的功能，我们必须先将此问题分解成一连串的步骤，称为程序规划。首先，以流程图的方式，来确保整个程序在逻辑上没有问题（不用说了吧！什么语言都要有此步骤）。这种模块化的规划方式，称之为“由上而下的程序规划”。而在真正写程序时，却是从最小的单位模块（子程序）开始，当每个模块都完成之后，再合并成大程序；这种大处著眼，小处著手的方式称为“由下而上的程序设计”。

　　我们的第一个模块是BINIHEX，其主要用途是从8086的BX寄存器中取出二进制数，并以十六进制方式显示在屏幕上。注意：子程序如不能独立运行，实属正常。
　　 binihex segment
　　 assume cs:binihex
　　mov ch,4 ;记录转换后的十六进制位数（四位）
　　rotate: mov cl,4 ;利用CL当计数器，记录寄存器数位移动次数
　　rol bx,cl ;循环寄存器BX的内容，以便依序处理4个十六进制数
　　mov al,bl ;把bx低八位bl内数据转移至al
　　and al,0fh ;把无用位清零
　　add al,30h ;把AL内数据加30H，并存入al
　　cmp al,3ah ;与3ah比较
　　jl printit ;小于3ah则转移
　　add al,7h ;把AL内数据加30H，并存入al
　　printit:mov dl,al ;把ASCII码装入DL
　　mov ah,2
　　 int 21h
　　 dec ch ;ch减一，减到零时，零标志置1
　　jnz rotate ;JNZ：当零标志未置1，则跳到指定地址。即：不等，则转移
　　int 20h ;从子程序退回主程序
　　binihex ends
　　 end

　　利用循环左移指令ROL循环寄存器BX(BX内容将由第二个子程序提供)的内容，以便依序处理4个十六进制数:1. 利用CL当计数器，记录寄存器移位的次数。2.将BX的第一个十六进制值移到最右边。利用 AND （逻辑“与”运算：对应位都为１时，其结果为１，其余情况为零）把不要的部份清零，得到结果：先将BL值存入AL中，再利用AND以0Fh（00001111）将AL的左边四位清零。由于０到９的ASCII码为30h到39h，而Ａ到Ｆ之ASCII码为41h到46h，间断了7h，所以得到结果：若AL之内容小于3Ah，则AL值只加30h，否则AL再加7h。ADD指令会将两个表达式相加，其结果存于左边表达式内。标志寄存器（Flag Register）是一个单独的十六位寄存器，有9个标志位，某些汇编指令（大部份是涉及比较、算术或逻辑运算的指令）执行时，会将相关标志位置1或清0， 常碰到的标志位有零标志（ZF）、符号标志（SF）、溢出标志（OF）和进位标志（CF）。 标志位保存了某个指令执行后对它的影响，可用其他相关指令，查出标志的状态，根据状态产生动作。CMP指令很像减法，是将两个表达式的值相减，但寄存器或内存的内容并未改变，只是相对的标志位发生改变而已：若 AL 值小于 3Ah，则正负号标志位会置0，反之则置1。 JL指令可解释为：小于就转移到指定位置，大于、等于则向下执行。CMP和JG 、JL等条件转移指令一起使用，可以形成程序的分支结构，是写汇编程序常用技巧。

　　第二个模块DECIBIN 用来接收键盘打入的十进制数，并将它转换成二进制数放于BX 寄存器中，供模块1 BINIHEX使用。
　　decibin segment
　　assume cs:decibin
　　mov bx,0 ;BX清零
　　newchar:mov ah,1 ;
　　int 21h ;读一个键盘输入符号入al，并显示
　　sub al,30h ;al减去30H，结果存于al中，完成ASCII码转二进制码
　　jl exit ;小于零则转移
　　cmp al,9d
　　 jg exit ;左>右则转移
　　cbw ;8位al转换成16位ax
　　xchg ax,bx ;互换ax和bx内数据
　　mov cx,10d ;十进制数10入cx
　　mul cx ;表达式的值与ax内容相乘，并将结果存于ax
　　xchg ax,bx
　　 add bx,ax
　　 jmp newchar ;无条件转移
　　exit: int 20 ;回主程序
　　decibin ends
　　 end
　　CBW 实际结果是:若AL中的值为正，则AH填入00h；反之，则AH填入FFh。XCHG常用于需要暂时保留某个寄存器中的内容时。
　　当然，还得一个子程序（CRLF）使后显示的十六进制数不会盖掉先输入的十进制数。
　　crlf segment
　　assume cs:crlf
　　mov dl,0dh ;回车的ASCII码0DH入DL
　　mov ah,2
　　 int 21h
　　 mov dl,0ah ;换行的ASSII码0AH入AH
　　mov ah,2
　　 int 21h
　　 int 20 ;回主程序
　　crlf ends
　　end

　　现在我们就可以将BINIHEX、DECIBIN及CRLF等模块合并成一个大程序了。首先，我们要将这三个模块子程序略加改动。然后，再写一段程序来调用每一个子程序。
　　crlf proc near；
　　mov dl,0dh
　　mov ah,2
　　int 21h
　　mov dl,0ah
　　mov ah,2
　　int 21h
　　ret
　　crlf endp

　　类似SEGMENT与ENDS的伪指令，PROC与ENDP也是成对出现，用来识别并定义一个程序。其实，PROC 真正的作用只是告诉编译器：所调用的程序是属于近程（NEAR）或远程（FAR）。 一般的程序是由 DEBUG 直接调用的，所以用 INT 20 返回，用 CALL 指令所调用的程序则改用返回指令RET,RET会把控制权转移到栈顶所指的地址，而该地址是由调用此程序的 CALL指令所放入的。
　　各模块都搞定了，然后我们把子程序组合起来就大功告成
　　decihex segment ;主程序
　　assume cs:decihex
　　org 100h
　　mov cx,4 ;循环次数入cx；由于子程序要用到cx，故子程序要将cx入栈
　　repeat: call decibin;调用十进制转二进制子程序
　　call crlf ;调用添加回、换行符子程序
　　call binihex ;调用二进制转十六进制并显示子程序
　　call crlf
　　loop repeat ;循环4次，可连续运算4次
　　mov ah,4ch ; 调用DOS21号中断4c号功能，退出程序，作用跟INT 20H
　　int 21H ; 一样，但适用面更广，INT20H退不出时，试一下它
　　decibin proc near push cx ;将cx压入堆栈，;
　　┇ exit: pop cx ;将cx还原; retdecibin endp binihex proc near push cx
　　┇ pop cx retbinihex endp crlf proc near
　　 push cx
　　┇ pop cx retcrlf endpdecihex ends end

　　CALL指令用来调用子程序，并将控制权转移到子程序地址，同时将CALL的下行一指令地址定为返回地址，并压入堆栈中。CALL 可分为近程（NEAR）及远程（FAR）两种：1.NEAR：IP的内容被压入堆栈中，用于程序与程序在同一段中。2.FAR：CS 、IP寄存器的内容依次压入堆栈中,用于程序与程序在不同段中。PUSH、POP又是一对指令用于将寄存器内容压入、弹出，用来保护寄存器数据，子程序调用中运用较多。堆栈指针有个“后进先出”原则，像PUSH AX，PUSH BX…POP BX，POP AX这样才能作到保护数据丝毫不差。

　　汇编语言超浓缩教程到这要告一段落了，希望能奠定你独立设计的基础。而更多更好的技巧则全依赖你平时的积累了。祝你成功！
　