8086汇编语言学习8086汇编开发环境搭建和debug模式介绍

xiaoxiongcanguan xiaoxiongcanguan     2023-04-26     126

关键词:

1. 8086汇编开发环境搭建

  在上篇博客中简单的介绍了8086汇编语言。工欲善其事,必先利其器,在8086汇编语言正式开始学习之前,先介绍一下如何搭建8086汇编的开发环境。

  汇编语言设计之初是用于在没有操作系统的裸机上直接操作硬件的,但对于大部分人来说,在8086裸机上直接进行编程将会面临各种困难。好在我们可以使用软件模拟器来模拟硬件进行8086的学习实践。在《汇编语言》中作者推荐通过windows环境下的masmdebug进行学习。

masm介绍:

  masm是一款DOS下的汇编工具包,在8086汇编的学习中我们需要其中的几个文件,分别是masm.exelink.exe

  masm.exe 汇编器,用于将文本格式的汇编语言源文件编译为.obj结尾的二进制文件,其生成的.obj结尾的二进制目标文件是被编译的源文件的对应的机器码。单独的源程序目标文件通常是无法直接运行的,还需要和互相依赖的其它同样编译完成的二进制文件链接在一起才能生成最终的可执行文件(比如所需要的静态库函数) 。因此,obj文件通常也被叫做中间文件。

  link.exe 链接器,obj文件需要通过链接才能转换成可执行程序,而链接器就是负责完成这一任务的。链接器能将多个obj目标文件以及其所依赖的库程序进行统一处理(例如多个目标文件中指令、数据内存地址的偏移处理),并生成可执行文件。

debug介绍:

  debug.exe 调试器,windows提供了一个在dos中调试8086汇编程序的工具debug.exe,提供了展示程序运行时CPU中各寄存器、内存中数据指令级的单步调试等功能。debug程序的使用会在本篇博客的后半段进行详细介绍。

64位操作系统兼容性问题:

  由于《汇编语言》一书出版较早,当时的windows系统还是32位的,32位windows系统都默认安装了masm与debug,能打开dos窗口直接使用。但目前普遍使用的、新的windows 64位操作系统中却并没有默认提供masm工具包和debug.exe,同时masm、debug也与64位的windows系统版本不兼容。

想在64位的windows系统下使用masm、debug有两个常用方法:

  1. 通过虚拟机安装一个老版本的windows操作系统(推荐windows xp)

  2. 通过DOSBox这一轻量级的ms-dos模拟器来运行,但上文所述的依赖程序需单独下载(百度网盘下载链接:https://pan.baidu.com/s/158NKJoea6_Y4UmCFsDP0oQ#list/path=%2F)

  个人推荐第二种方法,下面介绍如何在windows64位操作系统下使用DOSBox来搭建8086汇编语言的开发环境。

DOSBox安装与使用

DOSBox下载安装:

  DOSBox可以在官网下载,这里也提供了百度网盘的下载链接(0.74版本):https://pan.baidu.com/s/11_GcPpTqJm78N8xEXZpPMw

  安装完毕后,找到安装目录下的DOSBox.exe并启动,能看到如下图界面。

  技术图片

  作为dos的模拟器和普通的dos窗口没有明显区别,但是初始时并不能直接访问到本地磁盘,需要先将本地磁盘挂载到DOSBox中

DOSBox挂载本地磁盘:

  1. 在本地操作系统磁盘上选择一个文件夹目录,作为挂载的磁盘路径(例如C:dos)

  2. 在DOSBox启动的dos窗口中执行命令:mount C C:dos(代表着将本地的C:dos路径挂载到DOSBox的C盘路径下),能把dos窗口的工作目录切换到C盘,接下来就可以正常访问被挂载的磁盘路径下的内容了。

  3. 将前面提到过的debug.exe等文件都放在这个挂载的本地磁盘路径下(例如C:dos),通过DOSBox就可以兼容的运行masm工具包中的程序和debug.exe了

  技术图片

添加自动执行脚本以避免重复操作:

  由于上述DOSBox的磁盘挂载是临时的,每次重新启动DOSBox后都需要重新输入命令进行挂载,太麻烦了。我们可以通过修改DOSBox配置的方式,免去这些重复的操作。

  找到DOSBox安装目录下的DOSBox 0.74 Options.bat,使用系统自带的记事本直接打开,暂不研究其它配置段的作用,找到最后的【autoexec】段,配置在【autoexec】的内容会作为命令在DOSBox启动时按顺序被自动执行。  

  将挂载磁盘操作命令配置在【autoexec】段中能避免重复操作。修改并保存配置文件后,重新启动DOSBox,发现配置中添加的命令会被自动执行。

  技术图片

2. 8086debug模式介绍

  在搭建好了8086汇编的开发环境后,接下来介绍8086的debug模式。执行debug.exe以进入debug调试模式,在dos中通过输入命令的方式进行交互。

  技术图片

  debug模式下有20多种不同命令,限于篇幅这里只会介绍几个以后实验时常用到的命令。(通过回车执行命令,DOS下的命令默认是不区分大小写的)

R命令 查看/改变CPU寄存器内容

  R命令的作用是查看和修改debug模式下CPU中寄存器的值。

  (-r) 单独的输入r,可以查看当前CPU的内容

  (-r 寄存器名) r加上寄存器名可以在接下来的":"提示后输入新的值,以达到修改对应寄存器内容的目的(示例中第二行 AX 0000表示修改前寄存器AX的值为0000)  技术图片

D命令 查看内存中的内容

  D命令的作用是查看内存中的内容。

  D命令有许多不同的传参方式可供使用,先介绍最易理解的(段地址:偏移地址)查看方式。D命令默认会显示寻址地址开始的后128个内存单元的内容,以16进制的方式显示(每个内存单元8位,一行最多16个内存单元),而最右边会将内存单元中的二进制数据以ascll码的形式翻译展示。

  技术图片

  有时,我们只想聚焦于某一部分内存地址的内容,而默认展示的内存视图不是很方便。

  D命令提供了另外一种访问内存的方式(段地址:偏移起始地址 偏移终止地址),其能够展示(段地址:偏移起始地址 至 段地址:偏移终止地址)的内存信息,范围两端均为闭区间。

  技术图片

E命令 改变内存中的内容

  E命令的作用是改变内存中的内容

  和对CPU中寄存器的查看,修改不同,对内存进行查看和修改较为复杂,为此debug设计了两个不同的命令分别进行控制(E命令修改内存、D命令查看内存)。

  通过(E 起始地址 数据1 数据2 数据3...)命令可以修改内存中以起始地址开始,顺序的N个内存单元的值(N为实际参数传递的数量)。

  技术图片

   也可以和R命令修改CPU中寄存器值类似的,通过提示来修改特定内存单元的值。00.12  00代表内存单元在修改前的值,12是我们手动输入的、需要修改的新值。

  技术图片

  可以通过E命令向内存输入对应的机器指令,因为机器指令也是数据的一种

有以下指令(左侧为机器码,右侧为对应的汇编指令):

  B80100  mov ax,0001

  BB0200  mov bx,0002

  01D8      add ax,bx

  我们可以向内存1000:0处写入这些机器指令,以供接下来通过debug执行这段机器指令 (执行命令:E 1000:0 B8 01 00 BB 02 00 01 D8)。

  技术图片

U命令 将内存数据转换为汇编指令展示

  U命令的作用是将内存中的二进制数据转换为汇编指令展示(反汇编)。

  D命令能够将内存中的数据以16进制或ascll码的形式展现出来,但有时我们需要观察的是内存中的机器指令时,D命令的视图过于抽象,不利于理解。debug提供了U命令来解决这个问题。

  对于前面我们在1000:0处输入的机器指令,使用 U 1000:0 命令(u 内存地址)可以将内存中的数据以汇编语言指令的方式进行展示。

  技术图片

  可以观察到,左边展示的是内存地址,中间则是16进制的内存视图,右边展示的是内存中数据所对应的汇编指令(例如: 1000:0000B80100MOV AX,0001)。

  由于我们只输入了三条汇编指令,而后面内存中的数据并不是我们想要执行的,但U命令却依然将其以汇编指令的形式转换并显示出来了。

  这也是前一篇博客所提到的,内存中的数据完全是二进制的,既可以将其看做普通的二进制数据、十六进制数据、ascll码文本数据,也可以视作程序指令,这些二进制的"数据"的处理完全取决于如何对其进行解释

T命令 单步执行机器指令

  T命令的作用是进行单步机器指令的调试

  以上文通过E命令写入内存1000:0的三条指令举例,介绍如何使用T命令来让CPU执行1000:0处的机器指令。T命令用于单步调试,一次只会执行一条机器指令。

  8086CPU在运行时会将CS:IP寄存器所指向的内存单元中的内容解释为指令执行,要将内存1000:0处的内容作为指令执行必须先修改CS、IP两个寄存器的值,使之指向1000:0。

  技术图片

   先执行一次T命令,1000:0处的指令(mov ax,0001)便会被执行,可以观察到寄存器ax的值已经变成了0001;同时寄存器IP的值增加了3(mov ax,0001的指令长度为3),此时CS:IP指向的便是位于1000:3处的下一条指令(mov bx,0002),在视图的最后一行中也有所体现

   技术图片

   再执行一次T命令,会执行1000:3处的指令(mov bx,0002),可以观察到寄存器bx的值变成了0002;寄存器IP的值又增加了3(mov bx,0002的指令长度也是3),此时CS:IP指向的便是位于1000:6处的下一条指令(add ax,bx)

  技术图片

  最后执行一次T命令,add ax,bx会被执行(类似 ax=ax+bx)。寄存器ax的值已经变成了之前寄存器ax和bx中的数据之和0003;寄存器IP的值增加了2(add ax,bx的指令长度是2),CS:IP指向1000:8。

  技术图片

A命令 以汇编指令的形式向内存中写入内容

  A命令能够以汇编指令的形式向内存中写入内容

  对于内存操作,D命令可以查看内存中的内容,但如果想查看的是程序指令,显然U命令更加方便;E命令可以向内存中写入数据,但对于程序指令的写入,直接操作二进制机器码的方式过于硬核。为此,debug提供了A命令,我们可以通过A命令以汇编指令的形式向内存中写入内容。

  通过A命令将(mov ax,0001,mov bx,0002,add ax,bx)三条指令写入内存1000:0处:

  技术图片

  通过A命令进行指令的写入,和E命令达到的效果一样,但使用起来却更加便捷。A命令能够自动识别所输入汇编指令的长度,正确的在内存中写入程序指令。

  debug提供了D、E两种命令用于对内存进行通用的操作(纯二进制、十六进制数据的读、写)。

  对于程序指令,debug提供了U、A两种命令以更人性化的方式来读写内存中的指令内容。

三 总结

  在debug模式下可以模拟8086汇编非常自由的控制CPU和内存,这也是汇编语言的强大之处和魅力所在。

贴近硬件底层的编程能够让我们编写出来的程序非常高效,但也存在一些问题:

  1.内存中的内容被当做指令还是数据来处理完全取决于如何解释,编程时稍有不慎就会导致CPU执行一些不应该执行的指令,甚至造成巨大的破坏。

  2.在未来还会介绍如何使用汇编语言来实现高级语言中出现的结构体、数组等概念。这些数据结构完全是程序逻辑上的,内存本身可没有这些功能。因此在使用汇编访问内存中结构化的数据时,一不小心就会出现内存访问越界,错位等问题。

  3.汇编语言的抽象程度过低,许多在高级语言中很简单的功能在汇编中也需要很多的代码来实现(汇编实现的控制台打印hello world可能是常用语言中最繁琐的了)。

  编程语言的贴近底层与机器高效性如果站在更高的角度上看其实是一把双刃剑:直接操控底层的机器方便,机器执行效率高的同时,也是危险、开发效率底下的。汇编语言程序员不得不付出巨大的精力来仔细思考、斟酌这些底层机器层面的细节,以避免出现相关bug,大大降低了开发效率。这也是高级语言诞生,并不断发展的主要原因。

  高级语言大家族中按抽象程度来看,从偏底层的C,C++到java、python等,再到目前抽象程度最高的lisp。随着抽象程度的提高,离机器底层越远,执行效率通常也随之降低。但程序员所需要考虑的机器细节也就越少,能更专注于业务逻辑,进而提高了开发效率。比如在使用C编程时还需要仔细考虑指针错误,堆上无用内存回收等问题,到了更高级的java、python中,这些问题都交由编译器、虚拟机解决了,对开发人员也几乎透明了。

  天下没有免费的午餐,在选择适合的编程语言开发程序时,需要在机器执行效率和开发效率间做出取舍。但随着科学技术的发展,计算机硬件会越来越强大,对机器效率的担忧会越来越少,对程序开发效率的考虑将占据主导地位,越来越多的程序将会倾向于使用抽象程度更高的编程语言进行开发。

  虽然需要使用汇编语言的场合越来越少,但对汇编语言和底层机器硬件有一定的了解的话,依然能够帮助程序员更深刻的理解上层的知识内容、写出更高效的程序。

  毕竟,人类是无法抽象、封装到完美无缺的,有时还是你需要跳进下水道,深入底层一探究竟的。

  

8086汇编

8086汇编1、8086汇编介绍2、8086汇编内存交互3、8086汇编CPU寄存结构4、8086汇编Debug使用5、8086汇编段寄存器6、8089汇编标志寄存器7、8089汇编运算符指令8、8086汇编栈操作9、8089汇编源程序10、8086汇编程序编译11、8086汇编寻址方式12、8... 查看详情

8086汇编语言学习8086标志寄存器

8086标志寄存器介绍  前面已经介绍了8086大多数的寄存器,现在介绍一种8086内部一个特殊的寄存器,标志寄存器(flag register)。8086标志寄存器大致有以下作用:  1.存储一些相关指令的执行结果   2.为CPU执行相关指令提... 查看详情

汇编语言学习

零散记录:  8086CPU寄存器都为16位的,可存放两个字节;AX、BX、CX、DX这4个寄存器是通常用来存放一般性的数据,被称为通用寄存器。   AX:   以8086CPU而言,这四个寄存器都可分为两个可独立使用的8位寄存器使用,... 查看详情

win1064位配置8086汇编环境(代码片段)

一:工具准备Dosbox0.74-2;MASM工具地址:https://pan.baidu.com/s/1viOJVOvwwkGe0N2VZuNTqA二:工具安装1.Dosbox要安装在默认的盘中,不要变动(一般是C盘)2.从工具包中拷贝4个exe文件,放到一个自定义文件夹中三:环境配置1.打开Dosbox所在位置... 查看详情

windows环境下的32位汇编语言程序设计

...汇编,好友就分享了琢石成器——Windows环境下的32汇编语言设计,罗云彬的,书本还有附带的程序和动态链接库等等等等。。。  查看详情

8086汇编基础8086汇编语言用什么软件写?

...—————————————— 有的同学问我,8086汇编语言用什么写呀?那我就在这里说一下,其实我也就只是学了十几天的汇编语言,说的东西可能不太全面,还望包涵。 1dosbox(我自己拿VB6.0做的快捷方式 查看详情

outportb 和 8086 汇编中的 out 指令之间是不是存在显着差异?

】outportb和8086汇编中的out指令之间是不是存在显着差异?【英文标题】:Isthereasignificantdifferencebetweenoutportbandtheoutinstructionin8086assembly?outportb和8086汇编中的out指令之间是否存在显着差异?【发布时间】:2019-06-0215:53:54【问题描述... 查看详情

汇编学习8086cpu-段地址-偏移地址简要理解

这只是新手学习汇编的一个小笔记,帮助自己理解的,不建议观看! 最近刚开始学习汇编,看到了8086 CPU的寻址方式:物理地址=段地址*16+偏移地址,于是有了如下的一些问题:一、为何8086 CPU... 查看详情

8086汇编语言入门-helloworld

...://pan.baidu.com/s/1i5R9qO9  密码:rfgk  80x86微处理器汇编语言编程。学习任何编程语言都免不了要跨越HelloWorld这道坎,面向机器的汇编语言与面向过程/对象的高级语言不同,编码过程中对寄存器、内存的分配等细节都需要... 查看详情

复习8086汇编指令

CLI:clearInterupetSTI:setInterupetCLD:clearDirectorSTD:setDirector:::::::::::::::::::CLI和STI是屏蔽中断和设置中断用的。CLD与STD是用来操作方向标志位DF(DirectionFlag)。CLD使DF复位,即DF=0,STD使DF置位,即DF=1.用于... 查看详情

8086汇编第一部分:基本概念(代码片段)

一写在开头1.1本节内容本节主要内容是有关8086汇编语言程序设计的基本概念。 二8086CPU的基本知识2.1汇编语言机器语言的晦涩和难以阅读催生了汇编语言。汇编语言使用助记符来表示各种二进制指令,便于人们的阅读。因为... 查看详情

8086debug调试学习笔记(代码片段)

8086DEBUG调试学习笔记安装路径:D:\\DOSBox①mountcD:\\DOSBox②输入c:③再输入masm④输入汇编的文件名(如test)⑤link⑥再输入汇编的文件名⑦debugtest.exe-r查看寄存器-a-q使用Q命令来退出debug调试-t单步调试DATASEGMENTBUFDB'HELLO... 查看详情

汇编lahf指令学习-使用emu8086

LAHF  用于将标志寄存器的低八位送入AH,即将标志寄存器FLAGS中的SF、ZF、AF、PF、CF五个标志位分别传送到累加器AH的对应位,八位中有三位是无效的;使用emu8086看一下;开始运行之前;点flags按钮调出标志寄... 查看详情

8086 汇编中的基于索引寻址

】8086汇编中的基于索引寻址【英文标题】:Basedindexaddressinginassemblyfor8086【发布时间】:2014-02-1920:21:00【问题描述】:我对以下这行有点困惑:addax,[si+4]这是否取SI的值并将4H添加到它,然后将其添加到AX?例如,我们会说AX=1000和... 查看详情

8086汇编学习之代码段数据段栈段与段地址寄存器

同类学习笔记总结:(一)、8086汇编学习之基础知识、通用寄存器、CS/IP寄存器与Debug的使用(二)、8086汇编学习之DS寄存器、SS/SP寄存器(三)、8086汇编学习之[BX],CX寄存器与loop指令,ES寄存... 查看详情

8086汇编之call和ret指令

Ret和call也是转移指令,可是他们跟jmp不同的是,这两个转移指令都跟栈有关系。<1>ret用栈中的数据改动IP的地址,从而实现近转移(ip)=((ss)*16+sp)(sp)=(sp)+2相当于popip<2>retf用栈中的数据来改动CS以及IP的值,实现段... 查看详情

调试汇编代码(英特尔 8086)

】调试汇编代码(英特尔8086)【英文标题】:DebuggingAssemblyCode(Intel8086)【发布时间】:2010-07-0522:03:02【问题描述】:我正在上一门专注于intel8086架构的组装课程(所有编译/链接/执行都来自通过DOS-Box在win7上运行DOS)。我已经完... 查看详情

汇编 8086 中的 SHR 命令

】汇编8086中的SHR命令【英文标题】:SHRcommandinassembly8086【发布时间】:2019-02-2310:05:59【问题描述】:我得到了以下代码,我想在每一步之后写下观察结果。代码是:MOVAL,15MOVAH,0FFHXORAL,ALMOVCL,3SHRAX,CL现在唯一让我困惑的是SHR命令。... 查看详情