第3章 寄存器(内存访问)
# 第3章 寄存器(内存访问)
# 3.1 内存中的字存储
CPU 中用16位寄存器存储一个字,高8位存放高位字节,低8位存放低位字节。内存单元是字节单元,一个单元存放一个字节,一个字需要使用两个连续的内存单元进行存放,这个字的低位字节存放在低地址单元,高位字节存放在高地址单元
问题:
- 0地址单元存放的字节型数据是多少?20
- 0地址单元存放的字型数据是多少?4E20
- 2地址单元存放的字节型数据是多少?12
- 2地址单元存放的字型数是多少?0012
- 1地址单元存放的字型数据是多少?124E
# 3.2 DS 和 [address]
CPU 要读写一个内存单元的时候,必须给出这个内存单元的地址。内存单元的地址由段地址和偏移地址组成。DS 寄存器通常需要存放访问数据的段地址
mov bx,1000H
mov ds,bx
mov al,[0]
[0]:表示内存单元的偏移地址
指令执行的时候,CPU 自动取 ds 中的数据作为内存单元的段地址
mov al,[0]:表示数据从1000:0 单元到 al 的传送
2
3
4
5
6
7
mov ds,1000H 是非法的。
只能通过一个寄存器来进行中转,如 bx。
- mov bx,1000H
- mov ds,bx
# 3.3 字的传送
CPU 是16位结构,有16根数据线,可以一次性传送16位数据,就是一个字
# 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
add 和 sub 指令有以下几种形式:
- add 寄存器,数据 比如: add ax,8
- add 寄存器,寄存器 比如:add ax,bx
- add 寄存器,内存单元 比如:add ax,[0]
- add 内存单元,寄存器 比如:add [0],ax
- sub 寄存器,数据 比如:sub ax,9
- sub 寄存器,寄存器 比如:sub ax,bx
- sub 寄存器,内存单元 比如:sub ax,[0]
- sub 内存单元,寄存器 比如:sub [0],ax
# 3.5 数据段
总结
- 字在内存中存储,使用两个地址连续的内存单元存放,低位字节存放在低地址单元,高位字节存放在高地址单元
- 使用 mov 指令访问内存单元,可以在 mov 指令中只给出单元的偏移地址,此时段地址默认在DS寄存器中
- [address]表示一个偏移地址位 address 的内存单元
- 在内存和寄存器之间传动数据的时候,高地址单元和高8位寄存器,低地址单元和低8位寄存器相对应
- mov、add、sub 是具有两个操作对象的指令。jmp 是具有一个操纵对象的指令
# 3.6 栈
- 入栈:就是将一个新的元素放到栈顶
- 出栈:就是从栈顶取出一个新的元素
- 栈顶的元素总是最后入栈。
- 栈的这种操作规则被称为:LIFO(Last In First Out)后进先出
# 3.7 CPU 提供栈机制
基本命令就是 PUSH 和 POP,push ax 表示将寄存器 ax 中的数据送入栈中,pop ax 表示从栈顶中取出数据送入到 ax,CPU 入栈和出栈操作都是已字为单位进行的
段寄存器 SS 和 SP,栈顶的段地址存放在 SS 中,偏移地址存放在 SP 中,任意时刻 SS : SP 指向栈顶元素
下图描述了 8086CPU 对 push 指令的执行过程:
将 10000H ~ 1000FH 如果初始状态栈是空的,SS = 1000H,SP = ?
将 10000H~1000FH 这段空间当作栈段,SS = 1000H,空间大小为16节,最底部的字单元地址为 1000 : 000E。任意时刻,SS : SP指向顶,当栈中只有一个元素的时候,SS = 1000H,SP = 000EH。
栈为空,就相当于栈中唯一的元素出栈,出栈后,SP = SP + 2,SP原来为 000EH,加2后 SP = 10H,所以栈为空的时候,SS = 1000H,SP = 10H。
图3.12描述了 8086CPU 对 pop 指令的执行过程:
pop ax 的执行过程和 push ax 刚好相反,由下面两步完成:
- 将 SS : SP 执行的内存单元处的数据送入 ax 中;
- SP = SP + 2, SS :SP 指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。
注意:出栈后,SS : SP 指向新的栈顶 1000EH,pop 操作钱的栈顶元素,1000CH 处的2266H 依然存在,但是它已不在栈中。当再次执行 push 等入栈指令后,SS : SP 移至 1000CH,新数据将覆盖旧数据。
# 3.8 栈顶超界问题
CPU 不会保证我们对栈的操作不会超界。CPU 只知道栈顶 (SS : SP) 在何处,不知道安排的栈的空间由多大。所以编程的时候操心栈顶超界的问题。
# 3.9 栈的总结
初始化栈的代码
mov ax,1000H
mov ss,ax
mov sp,0010H ;
2
3
- 在 ss,sp 中存放栈顶的段地址和偏移地址:提供入栈和出栈的指令,他们根据 SS : SP 指示的地址,按照栈的方式访问内存单元
- push 指令的执行步骤:①sp = sp-2 ②向 ss : sp 指向的字单元中送入数据
- pop 指令的执行步骤:①从 ss :sp 指向的字单元中读取数据 ②sp = sp+2
- 任意时刻,ss : sp 指向栈顶元素
- CPU 只记录栈顶,栈空间的大小由我们自己管理
- 用栈来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序要和入栈的相反
- push,pop 实质是一种内存传送指令,注意他们灵活使用
总结:栈是一种非常重要的机制,一定要深入理解,灵活掌握
# 3.10 段的综述
我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元
我们用一个段存放数据,可以定义为 ==数据段==
我们用一个段存放代码,可以定义为 ==代码段==
我们用一个段当作栈,可以定义为 ==栈段==
==数据段:== 将段地址存放在 DS 中
==代码段:== 将它们的段地址存放在 cs 中,将段中的第一条指令的偏移地址存放在 IP 中,这样 CPU 就将执行我们定义的代码段中的指令
==栈段:== 段地址存放在 ss 中,将栈顶单元的偏移地址存放在sp中