3.《汇编语言》-王爽第三版学习笔记 寄存器(内存访问)

  1. 内存中的字存储
  • 字单元
    存放一个字型数据(16位)的内存单元,由两个地址梁旭的内存单元组成。高地址存高位字节,低地址存放地位字节。
  • N地址字单元
    起始地址为N的字单元。比如一个字单元由2,3两个内存单元组成,则这个字单元的起始地址为2,我们可以说这是2地址的字单元。
  • Example:


    7FCA58B7-98C0-46C1-8850-7A3B59E22C4A.png

    对于图中:
    (1)0地址单元中存放的字节型数据是 20H
    (2)0地址字单元中存放的字型数据 4E20H
    (3)2地址单元中存放的字节型数据是 12H
    (4)2地址字单元中存放的字型数据 0012H
    (5)1地址字单元中存放的字型数据 124EH

  1. DS 和 [address]
  • DS 8086CPU中的段寄存器,用来存储需要访问数据的地址段
  • [address] 表示一个内存单元,其中address表示内存单元的偏移地址
  • 内存单元的地址 = SA(ds中的数据为内存单元的段地址) * 16 + EA([address]偏移地址)
  • 8086CPU不支持将数据直接送入段寄存器的操作。所以只能用寄存器进行中转。
  • Example 1 将10000H(1000:0) 中的数据读到al中
mov bx,1000H
mov ds,bx
mov al,[0]
  • Example 2 将 al 中的数据存入内存单元10000H(1000:0)中
mov bx,1000H
mov ds,bx
mov [0],al
  1. 字的传送
    8086CPU是16位结构,有16根数据线,可以一次传送16位的数据(一个字),所以只要在mov指令中给出16位的寄存器就可以进行16位数据的传送了。

  2. mov add sub指令

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], ds
mov 段寄存器, 内存单元     // mov ds, [0]
add  寄存器,数据     // add ax,8
add  寄存器,寄存器     // add ax,bx
add  寄存器,内存单元     // add ax,[0]
add  内存单元,寄存器     // add [0],ax
sub  寄存器,数据     // sub ax,8
sub  寄存器,寄存器     // sub ax,bx
sub  寄存器,内存单元     // sub ax,[0]
sub  内存单元,寄存器     // sub [0],ax
  1. 数据段
    编程时的一种安排,将一组长度为N(N<=64KB),地址连续,起始地址为16倍数的内存单元当作专门存储数据的内存空间。
  • Example 将123B0H ~ 123B9H 的内存单元定义为数据段。
    (1)累加这个数据段中的前3个单元中的数据
mov ax,123BH
mov ds,ax
mov al,0
add al,[0]
add al,[1]
add al,[2]

(2)累加这个数据段中的前3个字型数据

mov ax,123BH
mov ds,ax
mov ax,0
add ax,[0]
add ax,[2]
add ax,[4]
  • 小结
    (1)字在内存中存储时,要用两个地址连续的内存单元存放,字的地位放在低地址单元,高位放在高地址单元。
    (2)用 mov 访问内存单元,可以再mov中只给出偏移地址,段地址默认在段寄存器DS中。
    (3)[address]表示一个偏移地址为 address的内存单元
    (4)在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器,低地址单元和低8位寄存器相对应
    (5)mov,add,sub 是具有两个操作对象的指令,jmp是具有一个操作对象的指令

  • 练习

(1)在Debug中, 用 "d 0:0 1f" 查看内存,结果如下:
0000:0000 70 80 F0 30 EF 60 30 E2-00 80 80 12 66 20 22 60
0000:0010 62 26 E6 D6 CC 2E 3C 3B-AB BA 00 00 26 06 66 88
下面的程序执行前, AX = 0, BX = 0, 写出相关寄存器中的值
mov ax 1
mov ds ax         // ds = 1
mov ax,[0000]   // AX = 2662H
mov bx,[0001]   // BX = E626H
mov ax,bx         // AX = E626H
mov ax,[0000]   // AX = 2662H
mov bx,[0002]   // BX = D6E6H
add ax,bx          // AX = FD48H
add ax,[0004]   // AX = 2C14H
mov ax,0          // AX = 0H
mov al,[0002]   // AX = 00E6H
mov bx,0          // BX = 0H
mov bl,[000C]   // BX = 0026H
add al,bl           // AX = 000CH
AF017D58-B4BA-4B5C-9652-BE2D971EA324.png
执行指令如下:
mov ax,6622H
jmp 0ff0:0100
mov ax,2000H
mov ds,ax
mov ax,[0008]
mov ax,[0002]
15C2843E-C084-4C73-9C72-449BAFB398F5.png

  1. 一种数据结构。操作规则 LIFO(Last In First Out 后进先出)

7.CPU提供的栈机制

PUSH ax  // 表示将寄存器ax中的数据送入栈中
POP ax  //表示取出栈顶数据存入寄存器ax中
  • 8086CPU入栈和出栈都是以字为单位进行的。
  • 8086CPU中 段寄存器 SS 和寄存器 SP,段地址存放在SS中,偏移地址存放在SP中。任意时刻,SS:SP 指向栈顶元素, PUSH POP执行时,CPU从中取出栈顶地址


    8FD03AE2-A6A2-43C9-8B70-564517009023.png
  • 8086CPU入栈时,栈顶从高地址向低地址方向增长。


    D9DFF7D5-0FC9-4F0C-B7D7-AA03245D344B.png
  1. 栈顶超界问题
    8086CPU只知道栈顶在何处(由SS:SP知识),而不知道安排的栈空间有多大,所以在编程的时候自己操作,根据可能用到的最大空间来安排栈的大小,执行出栈入栈的时候要注意可能导致栈超界问题。

9.PUSH POP指令

push 寄存器    //将一个寄存器中的数据入栈
pop 寄存器    //出栈,用一个寄存器中接受出栈的数据
push 段寄存器    //将一个段寄存器中的数据入栈
pop 段寄存器    //出栈,用一个段寄存器中接受出栈的数据
push 内存单元    //将一个内存单元中的字入栈(注意:战的操作以字为单位)
pop 内存单元  //出栈,用一个内存字单元接受出栈的数据
  • 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)PUSH POP实质上是一种内存传送指令
  1. 栈段
  • 数据段 段地址存放在 DS中,用mov add sub 等访问内存单元指令,CPU就将我们定义的数据段的内容当做数据来访问
  • 代码段 段地址存放在 CS中,将段中的第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义在代码段中的命令
  • 栈段 段地址存放在 SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作的时候,比如执行push,pop等指令,就将我们定义的栈段当做栈空间来用。
  • Debug T命令在执行修改寄存器SS的指令时,下一条指令也紧接着被执行。

你可能感兴趣的:(3.《汇编语言》-王爽第三版学习笔记 寄存器(内存访问))