3 寄存器(访问内存)
3.1 内存中字的存储
(小端存储原则):高地址存放字型数据的高位,低地址存放字型数据的低位;
字单元:存放一个字型数据(16位)的内存单元,有两个连续的内存单元构成,该字单元的起始地址成为N,称该单元位N地址字单元;也可称为由高位字节单元、低位字节单元组成。
3.2 ds段地址寄存器
顾名思义:自动保存段地址的寄存器
三句指令让CPU自己定位段地址:
8086CPU不支持直接把十六进制数传送到ds段寄存器中,只能使用下面指令间接修改。(原因是该CPU硬件设计问题)
mov bx,1000
mov ds,bx
mov al,[0] //最终将ds:0地址存放的数据放入al寄存器
//[]说明操作对象是一个内存单元,[0]说明便宜地址是0,它的段地址默认存放在ds寄存器中
//执行该指令时,8086CPU会从ds寄存器中取出段地址
3.3 数据段
在内存中的数据,不管是指令还是数据,都是一样的
使用cs:ip可以指定CPU执行指令的地址
使用ds:[address]可以指定CPU拿取数据的地址
假设,将123B0H~123B9H的内存单元定义为数据段,求前三个单元数据的和
mov ax,123B
mov ds,ax
mov al,0
add al,[0]
add al,[1]
add al,[2]
3.4 小结
- 字在内存中存储时,用两个连续地址的内存单元来存放(字型数据),字的高位字节放在高位地址,低位字节放在地位地址。(小端存放)
- 用mov指令访问内存单元,可以只给出偏移地址,段地址默认在ds寄存器中
- [address]表示一个偏移地址为address的内存单元
- 在内存和寄存器之间传送数据时,高地址单元和高8位寄存器、低地址和低8位寄存器相对应
- mov、add、sub是具有两个操作对象的指令,jmp只有一个操作对象的指令
3.5 栈
栈的规则:LIFO(last in first out):后进先出
CPU都有栈的设计:以栈的方式使用内存(以字节为单位)
push ax //把寄存器ax的数据入栈操作
pop ax //把栈顶元素出栈放入寄存器ax中
注意:这两条指令会根据寄存器的位数计算取出数据的字节大小
1)CPU如何知道这段空间是栈空间,如何确定栈顶的位置
8086寄存器中段寄存器ss和寄存器sp,栈顶的段地址存放在SS寄存器中,偏移地址存放在SP寄存器中。
任何时刻,SS:SP指向栈顶元素。push和pop指令执行时,CPU会从这两个寄存器中得到栈顶元素地址。
下面是入栈PUSH操作的内存变化
出栈:
- 将ss:sp栈顶元素出栈
- 再将sp += 出栈元素的大小(byte)
2)设置一个栈
-
确定起始的地址(例如2000:0)
-
计算需要栈的大小(10H的倍数最好,例如:10H—>16字节)
-
栈顶位置ss:sp = 起始地址 + 栈大小(2000:0010H)
问题:图中所示(中断机制)
mov ss,ax
mov ss,bx
mov ss,[0]
pop ss等指令都会出现一次执行后面语句也会执行
然后接着执行就好了
3)栈顶越界问题
假设栈的起始位置是2000:0000,(20000H),栈大小10H(16字节),栈顶位置就是ss:sp(2000:0010),所以栈的地址范围就是2000:0000~2000:0010,如果一直入栈操作(出栈操作),当ss:ip位置是2000:0000位置时,说明栈满了,再进行一次入栈操作,就会出现越界问题。
栈越界操作演示:
接着一顿操作执行后:我的dos程序被意外终止了,CPU收到一个非法指令,我又在dosbox软件中进行了上述操作却发现,修改成功了,但是改变不了ss:sp越界的事实。
严重性:假设越界后,修改了其他地址的内容(可能是指令,可能是数据),都会造成很大的影响。
4)栈的极限大小
假设连续入栈操作32768次,最终sp == 0的时候也会导致越界问题。
3.6 栈的作用
call指令调用函数,进入函数,执行完语句后,最后ret退出函数,cpu是怎么知道下一条的指令的。
此时
栈的作用:
-
临时保存数据
- 保存了call调用后,ret应该回退的cs:ip位置
- 函数调用前使用寄存器ax,push ax,在函数内改变了ax的值,函数执行结束,pop ax。这样就算函数内修改了ax的值,也是在栈中可以取回的。
-
进行数据交换
- 使用后进先出的原则
mov ax,1000 mov ss,ax mov sp,10 mov ax,2233 mov bx,4455 push ax push bx pop ax pop bx
3.7 总结
1)如何让CPU去按照安排去访问内存段呢
- 数据段:ds段地址寄存器:偏移地址[] 来确定数据段的位置。
mov ax,[0] //把ds:0位置的数据放入ax寄存器
add ax,[0]
sub ax,[0]
push [0]
pop [0]
...
-
指令段:使用cs:ip指向的地址作为cpu访问指令段的地址
-
栈段:通过改变ss:sp栈顶标记的位置去改变栈段的位置
2)内存段的安全
随意向一段未知的内存空间中写入内容是十分危险的行为
安全的内存空间:
0:200~0:2FFH只有256个字节
使用操作系统分配的内存空间(安全的):
- 系统加载程序时为程序分配内存
- 程序在运行过程中再去申请内存
段的地址
- 栈段:通过改变ss:sp栈顶标记的位置去改变栈段的位置
2)内存段的安全
随意向一段未知的内存空间中写入内容是十分危险的行为
安全的内存空间:
0:200~0:2FFH只有256个字节
使用操作系统分配的内存空间(安全的):
- 系统加载程序时为程序分配内存
- 程序在运行过程中再去申请内存