「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」。
段寄存器
- 数据和指令的区别
内存中存放的数据都是十六进制的数据,如果这些十六进制数据被标记为数据,那么cpu在读取的时候,读到多少就是多少,如果被标记为了指令,那么cpu会将这些十六进制转成指令进行执行
cpu只是个无情的计算机器,它无法自动区分数据和指令,标记需要我们告诉cpu
那么 如何给数据进行标记呢?
- 段寄存器的种类
DS---->data segment
SS---->stack segment
CS---->code segement
ES---->extra segement
都是用于存放段地址的
实际物理地址=段地址*16:偏移地址 10*10=100
71001 = 0710*16:0001
DS寄存器用于存放数据的段地址,那么数据所对应的偏移地址可以使用bx寄存器进行存放,使用DS寄存操作的内存数据都被当成是纯数据,里面存的是什么,读出来的就是什么
mov ax,3000H ;这行代码会转成16进制的数据存放到内存中 这些数据所对应的段地址默认放在ds寄存器中 ,使用ds进行读取的时候 读取的是该指令对应的16进制数据, 而不是被还原成了指令进行执行
CS寄存器用于存放指令所在的段地址,IP寄存器存放的是当前正在执行的指令所对应的偏移地址,所有使用CS:IP进行操作的内存数据都被当成是指令对待,读取的时候会将16进制数据转成对应的指令并执行
mov bx,3333H ;假如这条这条指令数据所对应的物理地址为0710:0000
mov ax,2000H ;假如这条这条指令数据所对应的物理地址为0710:0003
;如果我想跳过第一条指令 直接执行第二条指令 那么直接修改CS:IP的值为0710:0003即可
SS寄存器用于存放栈空间对应的段地址,所有被SS操作的内存空间都被当成栈空间进行对待,你想让哪部分内存空间当作栈空间,完全取决于开发者,sp寄存器存放栈空间偏移量,ss和sp配合使用
mov ax,0710H
mov ss,ax
mov sp,20 ;将0710:0000~0710:0014H 这20个字节的内存空间定义为栈空间
ES寄存器一般用于DS的替补,DS被占用无法使用时,临时使用ES替代,用法和DS一致
栈空间的操作
栈段里面存放也是数据和数据段无异,只不过数据排列的方式不一样,正常的排列方式是数据从低地址往高地址进行偏移存放,读取数据也是从低到高,而栈则是写入数据从高到低进行偏移,读取数据从低地址到高地址
由于这个特性,所以我们在定义一块空间作为栈空间使用时,都会先往高地址偏移一段空间
栈存储特点:
-
一次读写两个字节的数据
-
数据高地址往低地址逆序偏移存放
-
栈空间的声明
前面提到过,使用ss寄存器进行标记的空间为栈空间
data segment db 0,0,0,0,0,0,0,0 ;定义数据相当于是开辟了一块未标记内存空间,这块空间可以当作是数据空间也可以栈或者指令空间,却决于该段地址是由哪个段寄存器进行管理的 data ends code segment start: mov ax,data mov ss,ax ;该空间被ss指向,因此被当作是栈空间 如果是被CS指向则被当成指令空间,里面存放的数据都会被当成指令进行执行 mov sp,8 code ends end start
-
往栈空间中写入数据
使用push指令
data segment
db 0,0,0,0,0,0,0,0
data ends
code segment
start:
mov ax,data
mov ss,ax
mov sp,8
mov ax,2000H
push ax ;一次写入两个字节的数据,如果使用al编译报错
code ends
end start
-
从栈空间读取数据
使用pop指令
data segment db 0,0,0,0,0,0,0,0 data ends code segment start: mov ax,data mov ss,ax mov sp,8 mov ax,2000H push ax pop bx ;一次读取两个字节的数据,如果使用bl编译报错 code ends end start
思考:栈空间和数据段空间,里面存放的都是数据,那么是否可以使用SS来存放数据段的段地址呢,答案是可以的, 当SS充当数据段的时候,读写操作和DS一样,SS:[N],如果充当栈段的时候,读写操作时候时候pop和push,
由于pop和push默认以SS寄存器中的数据当做栈段地址,因此不能使用其他段寄存器充当栈段寄存器