[汇编语言]寄存器(内存访问)学习笔记

    选择打赏方式

3.1内存中字的存储

字单元的概念:字单元,即存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成。高地址内存单元中存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节。


3.2 DS和[address]

CPU要读写一个内存单元的时候,必须先给出这个内存单元的地址,在8086PC中,内存地址由段地址和偏移地址组成。8086CPU中有一个DS寄存器,通常用来存放要访问数据的段地址。比如我们要读取10000H单元的内容,可以用如下的程序段进行:
mov bx,1000H
mov ds,bx

mov al,[0]
上面的三条指令将10000H(1000:0)中的数据读到al中。

“[...]”表示一个内存单元,“[...]”中的0表示内存单元的偏移地址。段地址存储在ds中。

注意:8086CPU不支持将数据直接送入段寄存器。

3.3字的传送

例子:

mov bx,1000H 

mov ds,bx

mov ax,[0];1000:0处的字型数据送入ax 

mov[0],cx; cx中的16位数据送到1000:0处


TIM截图20180914114957.png


TIM截图20180914115118.png

TIM截图20180914115142.png


3.4 mov、add、sub指令

mov指令的几种形式

mov 寄存器,数据(比如:mov ax,8)

mov 寄存器,寄存器(比如:mov ax,bx)

mov 寄存器,内存单元(比如:mov ax,[0])

mov 内存单元,寄存器(比如:mov[0],ax)

mov 段寄存器,寄存器(比如:mov ds,ax)

mov 寄存器,段寄存器(比如:mov ax,ds)

mov 内存单元,段寄存器(比如:mov [0],cs)

mov 段寄存器,内存单元(比如:mov cs,[0])


add指令的几种形式

add 寄存器,数据(比如:add ax,8)

add 寄存器,寄存器(比如:add ax,bx)

add 寄存器,内存单元(比如:add ax,[0])

add 内存单元,寄存器(比如:add [0],ax)


sub指令的几种形式



sub 寄存器,数据(比如:sub ax,8)

sub 寄存器,寄存器(比如:sub ax,bx)

sub 寄存器,内存单元(比如:sub ax,[0])

sub 内存单元,寄存器(比如:sub [0],ax)



3.5 数据段

如何访问数据段中的数据呢?将一段内存当作数据段,是我们在编程时的一种安排,可以在具体操作的时候,用ds存放数据段的段地址,再根据需要,用相关指令访问数据段中的具体单元。

比如,将123B0H~123B9H的内存单元定义为数据段。现在要累加这个数据段中的前3个单元中的数据,代码如下。
mov ax,123BH

mov ds,ax;将123B日送入ds中,作为数据段的段地址

mov al,0;用a1存放累加结果
add al,[0];将数据段第一个单元(偏移地址为0)中的数值加到al中

add al,[1];将数据段第二个单元(偏移地址为1)中的数值加到al中

add al,[2];将数据段第三个单元(偏移地址为2)中的数值加到a1中

3.1~3.5小结
(1)字在内存中存储时,要用两个地址连续的内存单元来存放,字的低位字节存放在低地址单元中,高位字节存放在高地址单元中。
(2)用mov 指令访问内存单元,可以在mov指令中只给出单元的偏移地址,此时,段地址默认在DS寄存器中。
(3)[address]表示一个偏移地址为address的内存单元。
(4)在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器、低地址单元和低8位寄存器相对应。

(5)mov、add、sub是具有两个操作对象的指令。jmp是具有一个操作对象的指令。
(6)可以根据自己的推测,在Debug中实验指令的新格式。

3.6栈

栈是一种具有特殊的访问方式的存储空间。它的特殊性就在于,最后进入这个空间的数据,最先出去。(先进后出)

TIM截图20180916135621.pngTIM截图20180916135637.png


3.7 CPU提供的栈机制

8086CPU提供入栈和出栈指令,最基本的两个是PUSH(入栈)和POP(出栈)。

8086CPU中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。任意时刻,SS:SP指向栈顶元素。push指令和pop指令执行时,CPU从SS和SP中得到栈顶的地址。


push ax的执行,由以下两步完成:
(1)SP=SP-2,SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;
(2)将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈。

初始栈非空情况:TIM截图20180916140555.png

入栈时,栈顶从高地址向低地址方向增长。


初始栈为空情况:

任意时刻,SS:SP指向栈顶,当栈中只有一个元素的时候,SS=1000H,SP=000EH。栈为空,就相当于栈中惟一的元素出栈,出栈后,SP=SP+2,SP原来为000EH,加2后SP=10H,所以,当栈为空的时候,SS=1000H,SP=10H。


TIM截图20180916141438.png



pop ax的执行过程和push ax刚好相反,由以下两步完成:
(1)将SS:SP指向的内存单元处的数据送入ax中;
(2)SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

TIM截图20180916142332.png

注意,pop ax并不是把SS:SP指向的数据赋予ax后删除,而是把该数据赋予ax后,同时改变SS:SP,从而使该数据不属于栈。只有再次执行push等入栈命令后,才有可能改变该内存里面的数据。

3.8 栈顶超界的问题

TIM截图20180916155928.pngTIM截图20180916155952.png

栈空间之外有可能存放了其他用途的数据、代码等,这些数据、代码可能是我们自己程序中的,也可能是别的程序中的。所以栈顶越界会可能将这些数据、代码意外地改写,将会引发一连串的错误。8086CPU不保证我们对栈的操作不越界。它只知道栈顶在何处(由CS:IP指示),而不知道安排的栈空间有多大。所以,在编程的时候要自己考虑栈顶超界的情况,要根据可能用到的最大栈空间,来安排栈的大小,防止入栈的数据太多而导致的越界;执行出栈操作的时候也要注意,以防止栈空的时候继续出栈而导致越界。

3.9 push、pop指令
push和pop指令的格式:

push 寄存器;将一个寄存器中的数据入栈

pop寄存器;出栈,用一个寄存器接收出栈的数据


push段寄存器;将一个段寄存器中的数据入栈

pop段寄存器;出栈,用一个段寄存器接收出栈的数据


push内存单元;将一个内存字单元处的字入栈(注意:栈操作都是以字为单位。)

pop内存单元;出栈,用一个内存字单元接收出栈的数据

指令执行时,CPU要知道内存单元的地址,可以在push、pop指令中只给出内存单元的偏移地址,段地址在指令执行时,CPU从ds中取得。


push、pop实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据,与mov指令不同的是,push和pop指令访问的内存单元的地址不是在指令中给出的,而是由SS:SP指出的。同时,push和pop指令还要改变SP中的内容。


注意:push,pop等栈操作指令,修改的只是SP。也就是说,栈顶的变化范围最大为:
0~FFFFH。

栈的综述
(1)8086CPU提供了栈操作机制,方案如下:
在SS、SP中存放栈顶的段地址和偏移地址;提供入栈和出栈指令,它们根据SS:SP指示的地址,按照栈的方式访问内存单元。
(2)push 指令的执行步骤:1)SP-SP-2;2)向SS:SP指向的字单元中送入数据。
(3)pop指令的执行步骤:1)从SS:SP指向的字单元中读取数据;2)SP-SP+2;
(4)任意时刻,SS:SP指向栈顶元素。
(5)8086CPU只记录栈顶,栈空间的大小我们要自己管理。
(6)用栈来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序要和入栈的顺序相反。
(7)push、pop实质上是一种内存传送指令,注意它们的灵活应用。
栈是一种非常重要的机制,一定要深入理解,灵活掌握。


补充:
1、push pop只对字操作(不允许字节进栈)操作数长度为32位时进出栈为双字。
2、汇编语言中PUSH导致SP减2而不是加2。原因:栈在内存中实际存储结构是栈底在高地址,栈顶在低地址
3、8086push不可以使用立即数寻址方式(其他版本允许)
4、pop不可以使用立即数寻址方式,使用段寄存器时不可使用CS段寄存器。
5
从CPU的执行角度看,其实pushpop指令的执行顺序是完全一样的因此,不论push还是pop操作指令,都需要先将源操作数读入保存到CPU内部的临时寄存器里;然后改变栈顶指针;最后写入目标操作数

对于push指令,目标操作数是[sp] 
对于pop指令,源操作数是[sp]


3.10 栈段

我们可以将长度为N(N≤64K)的一组地址连续、起始地址为16倍数的内存单元当作栈使用,从而定义了一个栈段。

将一段内存当作栈段仅仅是在编程时的一种安排,CPU并不会因为这种安排就在执行pushpop指令的时候,将我们定义的栈段当作栈空间来访问(栈段的定义完全取决于程序员自身!CPU只认SS、SP。

换句话说栈段是我们人为定义的,本质上就是一段内存空间而已,cpu只认寄存器,其他的cpu根本不考虑。

一个栈段最大为FFFF的大小,这可以从两方面分析得到:

1. 在SS一定时,SP从0~FFFE;

2. 数学乘法原理2^N=2^16=64K=65535=FFFF

段的综述

cs代码段

ds数据段

ss栈段

一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么也不是。
关键在于CPU中寄存器的设置,即:CS、IP,SS、SP,DS的指向。






版权声明:若无特殊注明,本文皆为《 8964CN 》原创,转载请保留文章出处。
本文链接:[汇编语言]寄存器(内存访问)学习笔记 http://www.8964cn.net/?post=24
正文到此结束

热门推荐

发表吐槽

你肿么看?

你还可以输入 250 / 250 个字

嘻嘻 大笑 可怜 吃惊 害羞 调皮 鄙视 示爱 大哭 开心 偷笑 嘘 奸笑 委屈 抱抱 愤怒 思考 日了狗 胜利 不高兴 阴险 乖 酷 滑稽

评论信息框

吃奶的力气提交吐槽中...


既然没有吐槽,那就赶紧抢沙发吧!