Skip to content

Commit 4c933e6

Browse files
committed
workflow: register & memory
1 parent f860763 commit 4c933e6

File tree

2 files changed

+83
-4
lines changed

2 files changed

+83
-4
lines changed

doc/03-寄存器(内存访问).md

+83-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ cpu中用16位寄存器来存储一个字. 高8位存放高位字节, 低8位存
1111

1212
比如要读取10000H中的内容
1313

14-
```s
14+
```asm
1515
mov bx,1000H
1616
mov ds,bx
1717
mov al,[0]
@@ -47,7 +47,7 @@ mov,add,sub指令形式:
4747

4848
如将`123B0H~123B9H`的内存单元定义为数据段(起始地址`123BH`, 长度为`10`个字节),现在需要累加该数据段前3个单元中的数据
4949

50-
```s
50+
```asm
5151
5252
mov ax,123B
5353
mov ds,ax
@@ -64,7 +64,7 @@ add al,[2]
6464

6565
有如下指令
6666

67-
```s
67+
```asm
6868
mov ax,0123H
6969
push ax
7070
mov bx,2266H
@@ -98,4 +98,83 @@ pop cx
9898
1.`SS:SP`指向内存单元处的数据送入`ax`
9999
2. `SP=SP+2`,`SS:SP`指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶
100100

101-
![](../snapshots/3.12.png)
101+
![](../snapshots/3.12.png)
102+
103+
出栈后, `SS:SP`指向新的栈顶`1000EH`, 之前的栈顶`1000CH`处的数据`2266H`依然存在, 只是不再栈中. 当再次执行`push`等入栈指令后, `SS:SP`移至`1000CH`, 并在里面写入新的数据将其覆盖
104+
105+
## 栈空间超界问题
106+
107+
108+
8086CPU不保证对栈的操作不会超界. 8086CPU只知道栈顶在何处(由SS:SP指示),而不知道我们安排的栈空间有多大.
109+
110+
## push,pop指令
111+
push, pop等栈操作指令, 修改的只是`SP`. 栈顶的变化范围最大为`0~FFFFH`
112+
113+
8086CPU的栈操作机制:
114+
115+
1. 提供`SS`,`SP`指示栈顶
116+
2. 改变`SP`后写内存的入栈指令
117+
3. 读内存后改变`SP`的出栈指令
118+
119+
形式:
120+
| 指令 | 解释 |
121+
| ---- | ---- |
122+
| push 寄存器 | 将一个寄存器中的数据入栈 |
123+
| pop 寄存器 | 出栈, 用一个寄存器接收出栈的数据 |
124+
| push 段寄存器 | 将一个`段寄存器`中的数据入栈 |
125+
| pop 段寄存器 | 出栈, 用一个`段寄存器`接收出栈的数据 |
126+
| push 内存单元 | 将一个内存`字单元`处的字入栈(注: 栈操作都是以字为单位) |
127+
| pop 内存单元 | 出栈, 用一个`内存单元`接收出栈的数据 |
128+
129+
```asm
130+
mov ax,1000H
131+
mov ds,ax ;内存单元的段地址要放在ds中
132+
push [0] ;将1000:0处的字压入栈中
133+
pop [2] ;出栈, 出栈的数据送入1000:2处
134+
```
135+
136+
编程:
137+
1.`10000H~1000FH`这段空间当做栈,初始状态栈是空的
138+
2. 设置`AX=001AH, BX=001BH`
139+
3. 将AX,BX中的数据入栈
140+
4. 然后将AX,BX清零
141+
5. 从栈中回复AX,BX原来的内容
142+
143+
```asm
144+
mov ax,1000H
145+
mov ss,ax
146+
mov sp,0010H ;初始化栈顶
147+
mov ax,001AH
148+
mov bx,001BH
149+
150+
push ax
151+
push bx ;ax,bx入栈
152+
153+
sub ax,ax ;将ax清零, 也可以使用mov ax,0
154+
;sub ax,ax的机器码为2个字节
155+
;mov ax,0的机器码为3个字节
156+
sub bx,bx
157+
158+
pop bx ;从栈中回复ax,bx原来的数据,当前栈顶的内容是bx
159+
pop ax ;ax中原来的内容001AH在栈顶的下面, 所以要先pop bx,再pop ax
160+
161+
```
162+
163+
![](../snapshots/3.15.png)
164+
165+
166+
## 栈段
167+
168+
####
169+
我们可以将一段内存定义为一个段, 用一个段地址指示段, 用偏移地址访问段内的单元.这完全是我们自己的安排
170+
1. 数据段
171+
- 用一个段存放数据(ds寄存器)
172+
-`mov,add,sub`等访问内存单元的指令时,cpu就将数据段中的内容当做数据来访问
173+
2. 代码段:
174+
- 用一个段存放代码(cs寄存器)
175+
- 将断种第一条指令的偏移地址放在ip寄存器中,cpu就将执行代码段中的指令
176+
3. 栈段:
177+
- 用一个段当做栈(ss寄存器)
178+
- 将栈顶单元的偏移地址放到sp寄存器中,cpu在执行`push,pop`指令时将栈段当做栈空间来用
179+
180+
一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以都不是. 关键在于cpu中寄存器的设置,即`cs,ip,ss,sp,ds`的指向

snapshots/3.15.png

203 KB
Loading

0 commit comments

Comments
 (0)