汇编学习教程:访问内存(1)

引言

哈喽大家好,在这里首先祝大家:新年快乐,虎年大吉~~新的一年里,祝小伙伴们的工作蒸蒸日上,生活和和美美!

OK,下面开始我们本篇汇编学习教程。在上篇博文中,我们分析了本书中的第一个实验,针对实验的现象和问题探究,明白了对于8086PC机中内存正确分布方式,同时也加深了Debug工具的使用印象。那么本篇博文中,我们将正式开启CPU对于内存的访问学习,重点讲述我们之前说到的段寄存器:DS、SS,这两个寄存器的使用和意义。

内存中字的存储

我们通过之前的学习了解到,CPU中使用寄存器来存储数据,8086CPU是十六位寄存器,所以它的寄存器可存放一个字。对于内存而言,由一个个内存单元组成,每个单元存储一个字节的数据,一个字是两个字节,那么在内存中存放一个字,则需要两个内存单元,而这两个内存单元遵守高位对应高位,低位对应低位规则!

什么是“高位对应高位,低位对应低位”?这里举一个例子,比如:我们将20000(十六进制4E20H)这个数据存放到内存单元0开始的内存中,会是什么样子?如图所示:

我们发现,数字20000,十六进制4E20H,在内存中分布,0下标对应“20H”,1下标对应“4EH”。对于 4E20H 来说,20H是它的低位,4EH是它的高位;对于内存空间来说,0下标属于低位,1下标属于高位,根据“高位对应高位,低位对应地位”分布规则,则0下标存储对应数据的低位,所以 0->20H ,1下标存储对应数据的高位,所以 1->4EH。

总结一下,高位对应高位,这两个高位分别指数据的高位和内存空间的高位;低位对应低位,这两个低位分别指数据的低位和内存空间的低位

易混淆点1

这里出现第一个易混淆点:容易搞错寄存器中和内存中,一个字中的两个字节顺序。

我们发现,由于“高位对应高位,低位对应低位”规则,寄存器中的一个字,和内存中一个字,阅读顺序是相反的,这就导致很容易出现数据阅读错误。

比如数据 4E20H,在AX寄存器中存放,形式为“4E20H”,符合我们的习惯认知;数据放到内存中,使用0,1两个内存单元存放,按照我们的阅读习惯,则是“204EH”,这样与原数据两个字节顺序正好相反!

克服该易出错点的方法其实很简单,一定要死命牢记分布规则:高位对应高位,低位对应低位!

易混淆点2

内存中所谓的低位和高位,是相对而言的,不存在固定的单元它就是低位或者高位。

比如,我们使用内存单元0、1来存储数据 4E20H,此时,对于内存单元0、1来说,0是低位,1是高位。我们换一下,使用内存单元1、2来存储数据 4E20H,那么此时对于内存单元1、2来说,1是低位,而2是高位,所以就变成了1单元存储20H,2单元存储4EH。

那么问题就来了,到底什么时候我们才能确定这是低位这是高位呢?答案就是根据实际程序运行而定

比如代码中CPU需要从内存地址2000:0处读取一个字的数据到寄存器AX中,则此时地址单元 2000:0 是低位,该单元的字节数据放入AX寄存器中低位,2000:1 是高位,该单元的字节数据放入AX寄存器中高位。

DS段寄存器

DS是CPU中的一个段寄存器,全称:Data Segment.。

我们都知道Data是数据,所以DS的功能和作用和数据是脱不了干系。还记得CS段寄存器么?我们说过CS段寄存器中存放的是代码段的段地址,配套的还有一个IP寄存器用来存放代码段的偏移地址,两者CS:IP加在一起,指向了内存中的代码数据。

在讲段寄存器的时候我们有说过,对于一个程序来说,最重要的有两大块:1、逻辑代码;2、各种声明的变量。我们可以这样说,代码和变量组成了一个程序。在实际的开发中,我们通常会在代码中写好各种标量的声明,所以会变相的认为变量实际上是代码的一部分,这种想法其实是错误的。CPU执行程序,是严格将两者分割开来的,程序中的代码告诉了CPU如何执行如何操作,而程序中的变量就是CPU需要执行操作的数据。

CS:IP指明了代码,那么变量则由DS来指明。

与CS不同的是,DS段寄存器中存放的是数据段的段地址,任意时刻CPU将DS中地址下的数据当作真实数据来看待处理。

访问内存

我们都知道CPU的寻址方式是基地址加偏移地址得到目的地址,DS只给出数据段的段地址肯定是无法完成寻址,必然需要给出一个偏移地址才能进行寻址读取。下面我们将通过一个例子来进行内存的读取:

例如我们读取内存地址单元10000H下的数据到寄存器AL中。

首先我们确定目的地址为:1000:0,段地址为1000H,也就是说DS寄存器中存放的数据为1000H,我们可以使用MOV指令来设置DS寄存器值。

偏移地址为0则使用:[0]来表示。整体代码如下:

mov bx,1000H
mov ds,bx
mov al,[0]

上述三条指令执行完毕后,会将内存地址单元10000H下的数据放入AL中。

首先我们说前两条指令。

我们使用了两条MOV指令来给DS段寄存器赋值,为什么要这么做?MOV可不可以直接给DS段寄存器赋值?比如我们直接 mov ds,1000H ?

答案是当然不可以。因为DS是段寄存器,8086CPU不支持将数据直接送入段寄存器操作,所以 mov ds,1000H 是非法指令,无法执行。只能通过一个通用寄存器,先把数据赋值给通用寄存器,然后再由通用寄存器赋值给段寄存器,通过这种间接的方式来给段寄存器赋值。

下面说下最后一条指令:mov al,[0]

[...] 在指令中表示为一个内存单元,比如 [0] 中0则表示该内存单元的偏移地址,而该内存单元对应的段地址,则在DS中存放。CPU在执行该条指令时,会自动去取出DS中的数据当作内存单元的段地址来使用。

mov al,[0] 实际上是一个简略写法,为了加强理解,你完全可以写成 mov al,ds:[0],这样的看起来是不是清晰了很多呢。

使用Debug来执行

 我们此前学习了Debug工具的使用,还记得如何向内存写入汇编指令么?当然是A命令。那么下面就让我们使用Debug,来亲自执行并观察上述三条汇编指令执行结果。

打开Debug,使用A命令,向内存地址 2000:0 位置写入上述三条汇编指令

写入内存完成后,我们还需要一步,就是把CS:IP指向汇编指令所在的内存地址,这样CPU才会执行,使用R命令,修改CS、IP这两个寄存器的值:

 再使用R命令查看一下是否修改成功:

确实修改完成,我们能当到当前CS:IP 执行的汇编语句正是上述语句的第一条:mov bx,1000H 

这里可能会有一些疑问的地方,我们上述的汇编语句中,数字后面都是带有字母“H”,而Debug中,却没有字母“H”,1000H变成了1000,这是什么意思?

这其实也是一个易混淆点:

我们之前说到数字后面加一个字母“H”,表示这个数字是十六进制,例如1000H,则表示这个1000是十六进制下的1000,十进制表示为 4096。而在Debug中,显示的数据默认全部都是十六进制,不存在其他进制,所以就不需要增加字母“H”作以标明,在Debug中显示1000,就是表明这是十六进制1000。

解决了疑惑,那么接下来就让我们开始执行汇编语句,使用T命令进行单步执行:

 单步执行 mov bx,1000H后,我们可以看到BX 寄存器的值由之前的0变成了1000H,再执行一次T命令:

 单步执行 mov ds,bx后,我们可以看到DS段寄存的值由之前的073FH变成了1000H。这个时候我们注意到,图片右下角的 DS:0000=00 ,这个展示的是DS:0地址单元下的内容为0,我们观察到此时AX寄存器也为0,那么执行 mov al,[0],AL值还是不变的。

为了看到变化,我们这里修改下内存地址1000H:0单元的内容,使用E命令,将内容改为1;修改完成后使用D命令查看修改结果:

 地址1000H:0单元内容被修改为1,那么我们就可以执行最后一条汇编指令,使用T命令:

执行完成后,我们观察到AL值为1。至此我们完成了内存访问的全过程。

向内存中写入数据

在上面的讲述中,我们完成了从内存中读取数据的操作,那么如何向内存中写数据呢?

其实很简单,我们只需要把指令:mov al,[0],修改为:mov [0],al 即可。

MOV 指令就是拿右边的数据覆盖左边的数据,操作对象可以是寄存器也可以是内存单元,所以指令 mov [0],al ,意思就是将AL寄存器中的值放入内存地址DS:[0]单元中。

我们还是使用Debug来实际操作一下,使用A命令写入以下汇编指令:

mov bx,1000H
mov ds,bx
mov al,afH
mov [0],al

在上述汇编语句中,我们设置DS完毕后,设置AL寄存器值为 AFH,然后指令设置DS:[0]值为AL寄存器值。

使用T命令进行单步执行:

 接下来就是用D命令来查看1000H:0单元内容是否被修改:

 确实已经被修改为AFH,证明我们汇编指令执行成功。

本篇结束语

在本篇的学习中,我们学习了DS段寄存器的意义和它的使用,还有如何向内存中读写字节数据。理解了格式:[...]的含义和它与DS段寄存器之间的联系。

在下篇博文中,我们将学习和探讨如何使用DS段寄存器访问内存中的字数据。

感谢围观,转发分享请标明出处,谢谢!

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这本书的目的是为了让读者更好地理解计算机在相比于编程语言 如Pascal的更底层如何工作。通过更深刻地了解计算机如何工作,读者 通常可以更有能力用高级语言如C和C++来开发软件。学习汇编语言 来编程是达到这个目的的一个极好的方法。其它的PC汇编程序的书仍然 在讲授着如何在1981年使用在初始的PC机上的8086处理器上进行编程!那 时的8086处理器只支持实模式。在这种模式下,任何程序都可以寻址任 意内存访问计算机里的任意设备。这种模式不适合于安全,多任务操 作系统。这本书改为叙述在80386和后来的处理器如何在保护模式(也就 是Windows和Linux运行的模式)下进行编程。这种模式支持现在操作系统 所期望的特征,比如:虚拟内存内存保护。使用保护模式有以下几个原 因: 1. 在保护模式下编程比在其它书使用的8086实模式下要容易。 2. 所有的现代的PC操作系统都运行在保护模式下。 3. 可以获得运行在此模式下的免费软件。 关于保护模式下的PC汇编编程的书籍的缺乏是作者书写这本书的主要原 因。 就像上面所提到的,这本书使用了免费/开源的软件:也就是,NASM汇 编器和DJGPP C/C++编译器。它们都可以在因特网上下载到。本书同样 讨论如何在Linux操作系统下和在Windows下的Borland和Microsoft的C/C++编 译器中如何使用NASM汇编代码。所有这些平台上的例子都可以在我的网 页上找到:http://www.drpaulcarter.com/pcasm. 如何你想汇编和运行 这本教程上的例子,你必须下载这些样例代码。 注意这本书并不打算涵盖汇编编程的各个方面。作者尽可能地涉及了所 有程序员都应该熟悉的最重要的方面。 致谢
汇编语言》王爽著 经典学习汇编教程 汇编语言是各种CPU提供的机器指令的助记符的集合,人们可以用汇编语言直接控制硬件系统进行工作。汇编语言是很多相关课程(如数据结构、操作系统、微机原理等)的重要基础。为了更好地引导、帮助读者学习汇编语言,作者以循序渐进的思想精心创作了这本书。本书具有如下特点:采用了全新的结构对课程的内容进行组织,对知识进行最小化分割,为读者构造了循序渐进的学习线索;在深入本质的层面上对汇编语言进行讲解;对关键环节进行深入的剖析。 汇编语言是直接在硬件之上工作的编程语言,首先要了解硬件系统的结构,才能有效的应用汇编语言对其编程。 在本章中,对硬件系统结构的问题进行一部分的探讨,以使后续的课程可在一个好的基础上进行。 机器语言是机器指令的集合。机器指令展开来讲就是一台机器可以正确执行的命令。 这个是一本入门的汇编语言教材 关于内容:1、内容真的是做到了深入浅出(书是给人看的,别人看懂了才是最关键的)。2、有的地方看的出来是老师自己的感悟(不像其它国内大多数的书,就知道东抄一点西搬一点。内容到是什么都有,看了就不知道在讲个什么,什么都讲不清楚,就知道赚钱)我是学信息系?的学生,关于计算机科学方面我的这个专业学的不是太多,我就自己学,看了很多书,国内像这样的好书真的是很难得。3、更珍贵的是老师的编排,可以说比国外的还好(当然从知识点来说不如国外的书,但是这是一本入门书) 我的感想:1、计算机科学方面的好书,中国基本上没有(运用方面到是还是有很多不错的),要看就看国外的。翻译的好坏也是一个重点(像我英文不是很好,就只能看翻译过来的,看的时候还要看看翻译的是不是很好,有的翻译真的很烂),翻译的好的一般像潘爱民老师(听说雷迎春翻译的也不错,不过我还没看过他翻译的书).3、看的时候还要看是不是适合自己的情况(1、分清是入门教程还是高级教程;2、看看学过先导课程没有,有的知识是要有另外的知识做前提的) 目录: 第1章 基础知识 1.1 机器语言 1.2 汇编语言的产生 1.3 汇编语言的组成 1.4 存储器 1.5 指令和数据 1.6 存储单元 1.7 CPU对存储器的读写 1.8 地址总线 1.9 数据总线 1.10 控制总线 1.11 内存地址空间(概述) 1.12 主板 1.13 接口卡 1.14 各类存储器芯片 1.15 内存地址空间 第2章 寄存器 2.1 通用寄存器 2.2 字在寄存器中的存储 2.3 几条汇编指令 2.4 物理地址 2.5 16位结构的CPU 2.6 8086cPu给出物理地址的方法 2.7 “段地址xl6+偏移地址=物理地址”的本质含义 2.8 段的概念 2.9 段寄存器 2.10 CS和IP 2.11 修改CS、IP的指令 2.12 代码段 实验1 查看CPU和内存,用机器指令和汇编指令编程 第3章 寄存器(内存访问) 3.1 内存中字的存储 3.2 DS 31:1[address] 3.3 字的传送 3.4 ITIOV、add、sub指令 3.5 数据段 3.6 栈 3.7 CPU提供的栈机制 3.8 栈顶超界的问题 3.9 puSh、pop指令 3.10 栈段 实验2 用机器指令和汇编指令编程 第4章 第一个程序 4.1 一个源程序从写出到执行的过程 4.2 源程序 4.3 编辑源程序 4.4 编译 4.5 连接 4.6 以简化的方式进行编译和连接 4.7 1.exe的执行 4.8 谁将可执行文件中的程序装载进入内存并使它运行? 4.9 程序执行过程的跟踪 实验3 编程、编译、连接、跟踪 第5章 【BX】和loop指令 5.1 【BX】 5.2 Loop指令 5.3 在Debu9中跟踪用loop指令实现酮循环程序 5.4 Debu9和汇编编译器masm对指令的不同处理 5.5 loop和【bx】的联合应用 …… 第3章 寄存器(内存访问) 第4章 第一个程序 第5章 [BX]和loop指令 第6章 包含多个段的程序 第7章 更灵活的定位内存地址的方法 第8章 数据处理的两个基本问题 第9章 转移指令的原理 第10章 CALL和RET指令 第11章 标志寄存器 第12章 内中断 第13章 int指令 第14章 端口 第15章 外中断 第16章 直接定址表 第17章 使用BIOS进行键盘输入和磁盘读写 综合研究 附注

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值