8086汇编语言(03)
本文最后更新于231 天前,其中的信息可能已经过时,如有错误可以直接在文章下留言

1.内存中字的存储

如图,数据4E20H存放在内存中,8086CPU中是低字节的存放在低地址,而高字节的存放在高地址,这是一种小端序的存储模式,当然还有大端序的存储模式,在其他的领域会存在。

当我们问0地址单元存放的字节型数据是多少呢,就是20H,那0地址存放的字型数据应该是4E20H,同理问2地址单元存放的字型数据就是0012H,1地址存放的字型数据就是124EH,总之任何两个地址连续的内存单元,n单元和n+1号单元,可以将它们看成两个内存单元,也可以看成一个地址为n的字单元中的高位字节单元和低位字节单元。

2.DS和[address]

前面我们知道,8086CPU中内存地址由段地址和偏移地址组成,8086CPU中有一个DS寄存器,用来存放要访问的内存的段地址。

例如我们要读取10000H单元的内容可以用如下程序段进行

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

上面三条指令将10000H(1000:0)中的数据读到al中。为什么可以实现呢?

我们已经知道mov指令可完成两种传送功能:

1.将数据直接送入寄存器

2.将一个寄存器中的内容送入另一个寄存器中。

除此之外呢,mov指令还可以将一个内存单元中的内存送入寄存器当中,格式是

mov 寄存器名,内存单元地址

[address]表示一个内存单元,里面的数据表示的是偏移地址,如上面给出的汇编指令[0]就表示偏移地址为0,而执行指令的时候,8086CPU会自动取DS中的数据为内存单元的段地址。

上面的汇编指令中,我们事先将段地址1000H放入了ds寄存器当中,用mov al,[0],mov指令当中的[ ]说明操作对象是一个内存单元,[]中的0,说明这个内存单元的偏移地址为0。它的段地址默认放在了ds寄存器当中,

将段地址送入ds寄存器当中其实有一个易错点,上面给出的汇编指令中,我们先将1000H送入了bx寄存器中,再送入ds寄存器当中,那么能不能直接送入ds寄存器当中呢?

答案是不可以,8086CPU不支持将数据直接送入段寄存器ds当中。mov ds,1000H这样的汇编指令就是非法的。数据必须先进入通用寄存器当中,才可以被送入段寄存器当中。

上面所给的汇编指令是将内存单元的数据送入寄存器当中,我们想将寄存器当中的数据送入特点的内存单元当中也可以用以下代码完成。

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

3.字的传送

因为8086CPU是16位结构,有16根数据线,所以,可以一次性传送16位的数据,也就是一次性传送一个字

比如以下代码

mov bx,1000H
mov ds,bx
mov ax,[0]
mov [0],cx

将1000:0处的字型数据送入了ax当中,将cx中的16位数据送到1000:0处。因为ax是16位的寄存器,如果是al,ah啥的,就是字节型的数据。

做一道例题

首先段寄存器中的数据是1000H,执行第三行汇编指令时,索引到1000:0,即地址10000H处,因为ax是16位的数据,所以应该传送一个字大小的数据,数据1123被送入ax寄存器当中。

下一步同理bx中数据为6622,cx中数据为2211。执行最后两行汇编指令时,bx=bx+2211=6622+2211=8833,cx=cx+6622=2211+6622=8833。这里的bx和cx都指寄存器里面存储的数据。

所以答案为ax=1122,bx=8833,cx=8833。

4.mov、sub、add 指令

已学mov指令的几种形式如下

mov ax,6  # mov 寄存器,数据
mov bx,ax  # mov 寄存器,寄存器
mov ax,[0]  # mov 寄存器,内存单元
mov [0],ax  # mov 内存单元,寄存器
mov ds,ax  # mov 段寄存器,寄存器

还有下面这种也是可以实现的

mov ax,ds  # mov 寄存器,段寄存器

add和sub指令同mov一样,都是两个操作对象。

所有正确的语法如图

但是要注意add和sub指令无法对段寄存器进行操作

5.数据段

前面讲过我们可以根据需要将一组内存单元定义为一个段,前面讲了代码段,这里就谈谈数据段。

和代码段一样,可以将长度为 n (n<=64kb) 的一组代码,存在一组地址连续、起始地址为 16 的倍数的内存单元中,这段内存用来存放代码,从而定义了一个数据段。

如何访问数据段的数据呢?

和代码段同理,我们可以用ds存放数据段的段地址,再根据需要,用相关指令访问数据段中的具体单元。

数据段其实没啥好说的,我们通常简单汇编指令处理就是经常处理的是数据,一个段我们不用什么指令进行处理,那就是存储的一个数据。

6.栈

一个很重要的概念。

栈是一种具有特殊的访问方式的存储空间。她的特殊性就在于,最先进入这个空间的数据,最后出去。很形象的形容就是弹夹,最先进去的子弹一般最后打出去。

栈有两个基本的操作:入栈和出栈

入栈:将一个新的元素放到栈顶。

出栈:从栈顶取出一个元素。

栈顶的元素总是最后入栈,需要出栈时,又最先被从栈中取出来。栈的操作规则就是后进先出,先进后出。

8086CPU提供了相关的指令来以栈的方式访问内存空间,这意味着我们在操作内存空间时,可以将一段内存当作栈来使用。就像我们之前用CS来指定代码段差不多。

关于栈的汇编指令如下

push # 入栈
pop # 出栈
push ax # 将寄存器ax中的数据送入栈中
pop ax # 从栈顶取出数据送入ax

8086CPU的入栈和出栈操作都是以字为单位进行的。

用下图来加深理解

我们将这段内存空间看作栈,当我们执行前两条指令时,寄存器ax中的数据0123H首先被送入栈中,高字节在高地址,这点不用再强调了,后面继续执行三条push指令,把三个大小为字的数据送入了栈中。

当我们执行后面三条的pop指令时,会首先将1122H送出栈,并送入寄存器ax当中,后面两条同理。

最后栈中为空,寄存器ax存储的数据为1122H,寄存器bx存储的数据为2266H,寄存器cx存储的数据为0123H。

那么有两个问题,第一个问题和之前探讨数据段、代码段的时候差不多,CPU如何知道一段内存空间被当作段来使用了呢?

依旧是依赖寄存器,8086CPU当中有一个段寄存器SS(Stack Segment),用于存放栈顶的段地址。同时又有一个寄存器SP(Stack Pointer),用来存放栈顶的偏移地址。任意时刻,SS:SP都指向栈顶元素。

比如上图,当栈中没用任何元素的时候,SS中的地址就是指向1000,SP中的地址就是F。

第二个问题就是当执行push和pop指令的时候,如何知道哪个单元是栈顶单元呢?

如图

如图,解释的很清楚了。要注意的是,要先将寄存器SP中的数据减了2之后,数据才会被送入栈中。

pop呢,则是先把数据送出栈,然后再将寄存器SP的数据加2。为什么是加2和减2当然是因为push和pop指令操作的单位都是一个字来的。

还有一个点就是,当栈为空时,SS:SP其实指向的是最高地址单元的下一个单元。如上图就是10010H.

还有我们pop指令将一个数据送出栈时,这个数据还在栈当中存在吗?比如上图,可能我们会认为对第三张图中的栈执行了pop指令之后,2266H会被弹出栈,1000CH和1000DH的空间就是空的了,这样的想法其实是错的,在pop之后,数据依旧存留在栈中,只是在push之后,这两个单元的数据是会被覆盖的。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇