汇编语言(王爽)-寄存器(内存访问)


内存中字的存储

CPU中,用16位寄存器来存储一个字,高8位存放高位字节,低8位存放低位字节

内存中,一个内存单元存放一个字节,一个字则需要两个地址连续的内存单元来存放。字的低位字节存放在低地址单元中,高位字节存放在高地址单元中

1.png

0和1两个内存单元中存放数据4E20H

2和3两个内存单元中存放数据0012H

字单元

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

如上图

  1. 0地址单元中的字节型数据是20H

  2. 0地址字单元中存放的字型数据是4E20H

  3. 1地址字单元中存放的字型数据位124EH

由此可知,任何两个地址连续的内存单元,N号单元和N+1号单元,可以将它们看成两个内存单元,也可以看成一个地址为N的字单元中的低位字节单元和高位字节单元

DS和[address]

CPU要读写一个内存单元时,需首先给出这个内存单元的地址。

在8086PC中,内存地址由段地址和偏移地址组成

8086CPU中,DS寄存器用于存放要访问的数据的段地址

  1. 例:读取10000H内存单元的内容至al

    1
    2
    3
    mov bx,1000H
    mov ds,bx
    mov al,[0]
    1
    2
    3
    mov al,[0]

    格式:mov 寄存器名,内存单元地址

    [...]表示一个内存单元,[...]中的0表示内存单元的偏移地址

    在读取内存的指令执行时,8086CPU将自动取DS中的数据为内存单元的段地址,结合[...]中的偏移地址形成内存物理地址,即可将内存单元中的数据读取出来存到al

    8086CPU不支持将数据直接送入段寄存器的操作,只可用一个寄存器进行中转,即先将段地址送入通用寄存器,再由通用寄存器送入段寄存器

  2. 例:将al中的数据送入内存单元10000H中

    1
    2
    3
    mov bx,1000H
    mov ds,bx
    mov [0],al
    1
    2
    3
    mov [0],al

    格式:mov 内存单元地址,寄存器名

字的传送

8086CPU是16位结构,有16根数据线,可一次性传送16位的数据,即一个字

3.png

4.png

MOV,ADD,SUB指令

MOV指令

1
2
3
4
5
6
7
8
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 ds,[0]
1
mov 段寄存器,内存单元

2.png

ADD指令

1
2
3
4
add 寄存器,数据		add ax,8
add 寄存器,寄存器 add ax,bx
add 寄存器,内存单元 add ax,[0]
add 内存单元,寄存器 add [0],ax

SUB指令

减法指令

sub ax,9含义:用ax中的值减去9后保存到ax

1
2
3
4
sub 寄存器,数据		sub ax,9
sub 寄存器,寄存器 sub ax,bx
sub 寄存器,内存单元 sub ax,[0]
sub 内存单元,寄存器 sub [0],ax

数据段

可以将一组长度为N(N<=64KB),地址连续,起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段

定义数据段

5.png

操作数据段

1
2
3
4
5
mov ax,123BH
mov ds,ax
mov al,[0]
mov al,[1]
mov al,[2]

6.png

7.png

具有特殊访问方式的存储空间

基本操作:入栈,出栈

操作规则:LIFO(后进先出)

CPU提供的栈机制

8086CPU提供相关的指令来以栈的方式访问内存空间,即可以将一段内存当作栈来使用

1
2
3
4
5
push		;入栈
pop ;出栈

push ax ;将ax中的数据送入栈中
pop ax ;从栈顶取出数据送入ax

8086CPU的入栈与出栈操作以字为单位进行

CPU如何知道栈顶的位置

8086CPU中,有两个寄存器,段寄存器SS和寄存器SP

SS存放栈顶的段地址

SP存放栈顶的偏移地址

任意时刻,SS:SP指向栈顶元素

push指令和pop指令执行时,CPUSSSP中得到栈顶地址

不可直接向段寄存器SS送入数据,需使用通用寄存器中转

PUSH ax指令

  1. SP=SP-2,SS:SP指向当前栈顶上方内存单元,此单元为新的栈顶

  2. 将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新的栈顶

8.png

8086CPU中,入栈时,栈顶从高地址向低地址方向增长

POP ax指令

  1. SS:SP指向的内存单元处的数据送入ax中

  2. SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶

9.png

当栈顶数据执行了出栈操作,此数据并未在栈中删除,但其已经不存在于栈中了,因栈顶的地址是由SS:SP确定的,当其他数据执行入栈操作时,可覆盖已出栈的数据

栈空

10.png

任意时刻,SS:SP指向栈顶元素,当栈为空时,栈中没有元素,也就不存在栈顶元素,所以SS:SP只能指向栈的最底部单元下面的单元,该单元的偏移地址为栈最底部的字单元的偏移地址+2

栈顶超界问题

栈满超界

11.png

栈空超界

12.png

8086CPU无法提供任何机制判断对栈的操作是否超界。8086CPU只考虑当前的情况:当前的栈顶在何处、当前要执行的指令是哪一条。

所以只能靠程序员编程时注意出栈,入栈的栈的超界问题。

push、pop指令

pushpop指令可以在寄存器和内存之间传送数据

格式:

1
2
3
4
5
6
7
8
push 寄存器	;寄存器数据入栈
pop 寄存器 ;出栈至寄存器

push 段寄存器 ;段寄存器数据入栈
pop 段寄存器 ;出栈至段寄存器

push 内存单元 ;内存字单元数据入栈(栈操作以字为单位)
pop 内存单元 ;出栈至内存字单元

push指令与pop指令实质上是一种内存传送指令

栈段

将长度为N(N<=64KB)的一组地址连续,起始地址为16的倍数的内存单元,当作栈空间来使用,从而定义了一个栈段

将一段内存当作栈段,是程序员行为,CPU不会识别栈段,想要栈操作指令可以访问自定义的栈段,需将SS:SP指向自定义栈段


用机器指令和汇编指令编程

Debug的使用

D命令

d 段地址:偏移地址语句查看指定内存单元的内容

d 段寄存器:偏移地址,以段寄存器中的数据为段地址SA,列出从SA:偏移地址开始的内存区间中的数据

例:

  1. 1
    2
    3
    4
    5
    -r ds
    :1000
    -d ds:0

    查看从1000:0开始的内存区间中的内容

    13.png

  2. 1
    2
    3
    4
    5
    -r ds
    :1000
    -d ds:10 18

    查看1000:10-1000:18中的内容

    14.png

  3. 1
    2
    3
    -d cs:0

    查看当前代码段中的指令代码

    15.png

  4. 1
    2
    3
    -d ss:0

    查看当前栈段中的内容

    16.png

在E、A、U命令中使用段寄存器

D命令相同,使用段寄存器表示内存单元的段地址

例:

  1. 1
    2
    3
    4
    5
    -r ds
    :1000
    -e ds:0 11 22 33 44 55 66

    在从1000:0开始的内存区间中写入数据

    17.png

  2. 1
    2
    3
    -u cs:0

    以汇编指令的形式,显示当前代码段中的代码

    18.png

  3. 1
    2
    3
    4
    5
    -r ds
    :1000
    -a ds:0

    以汇编指令的形式,向1000:0开始的内存单元中写入指令

    19.png

下一条指令执行了吗?

debug中,用A命令写一段程序

1
2
3
4
5
6
7
mov ax,2000
mov ss,ax
mov sp,10 ;将2000:0000-2000:000F为栈空间,初始化栈顶
mov ax,3123
push ax
mov ax,3366
push ax ;向栈中压入两个数据

20.png

当使用T命令进行单步运行时,mov sp,10未执行,但是寄存器sp的值已经修改,说明mov sp,10mov ss,ax之后紧接着执行了

结论:DebugT命令在执行修改寄存器SS的指令时,下一条指令也紧接着执行了,这属于中断机制

---------------The End---------------
0%