汇编语言(三)--汇编指令与段的综述
本文最后更新于:2019年6月26日 晚上
概览:取指令过程、数据存取以及栈的概览,段的综述。
机器指令
机器指令也叫代码指令,是计算机能识别的一组二进制代码。
形如
1011 0000 0000 0111 B
把数“7”送到AL中
汇编语言指令
汇编语言有三种指令形式,分别是汇编指令、伪指令、宏指令。
并且汇编指令是从机器指令演化而来的,与机器密切相关。
汇编指令
汇编指令由操作码字段和操作数字段构成。
格式: 操作码字段 操作数字段
操作数字段可以是0个,1个,2个,3个。
双操作数
MOV AX,BX
格式:操作码 目的操作数,源操作数
目的操作数也是操作后的结果。
指令存取
CS : IP
这是8086CPU中最关键的寄存器,指出了CPU当前要读取指令的地址。
CS: 代码段寄存器,存放代码的段地址
IP: 指令指针寄存器,存放代码的偏移地址
8086取指过程
- 从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲区。
- IP=IP+所读取指令的长度,从而指向下一条指令。
- 执行指令,转到步骤1,重复此过程。
CPU区分指令与数据
内存中的指令与数据没有任何区别,都是二进制信息。CPU是将CS:IP指向的内存单元中的内容看做指令。
CPU将CS、IP中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中读取指令码,执行。
修改CS、IP指令
在CPU中,程序员能够通过指令读写的部件只有寄存器,程序员通过改变寄存器中的内容实现对CPU的控制。
mov指令不能用于设置CS、IP的值,8086CPU没有提供这样的功能。
转移指令-jmp指令可以修改,用指令中给出的段地址修改CS,偏移地址修改IP。
格式:jmp 段地址:偏移地址
jmp 2AE3:3
仅修改IP指令
用寄存器中的值修改IP。
格式:jmp 某一合法寄存器
jmp ax
代码段
将一段内存当作代码段,仅仅是我们在编程时的一种安排,CPU 并不会由于这种安排,就自动地将我们定义得代码段中的指令当作指令来执行。
CPU 只认被 CS:IP 指向的内存单元中的内容为指令,所以要将CS:IP指向所定义的代码段中的第一条指令的首地址。
数据存取
mov指令
mov bx,1000h
mov ds,bx
mov al,[0]
;将10000H(1000:0)中的数据读到al中。
- 将数据直接送入寄存器;
- 将一个寄存器中的内容送入另一个寄存器中。
- 将一个内存单元中的内容送入一个寄存器。
格式:mov 寄存器名,内存单元地址
“[…]”表示一个内存单元, “[…]”中的数字表示内存单元的偏移地址,其段地址是DS。
mov指令中的[]说明操作对象是一个内存单元,[]中的0说明这个内存单元的偏移地址是0,它的段地址默认放在ds中。
将数据送入段寄存器
mov ds,1000H;非法!
8086CPU不支持将数据直接送入段寄存器的操作!(硬件的问题)
数据->一般寄存器->段寄存器。
字的传送
如图所示,内存里一个存储单元只能存放一个字节(8位),而寄存器是16位的。
add、sub指令
栈
Last In First Out 后进先出
入栈:将一个新的元素放到栈顶;
出栈:从栈顶取出一个元素。
8086CPU的入栈和出栈操作都是以字为单位进行的。
push ax;将寄存器ax中的数据送入栈中
pop ax;从栈顶取出数据送入ax
CPU如何判断栈
寄存器CS和IP中存放着当前指令的段地址和偏移地址。
SS: 段寄存器,存放栈顶的段地址
SP:堆栈指针寄存器,存放栈顶的偏移地址
任意时刻,SS:SP指向栈顶元素
push指令执行过程
- SP=SP-2
- 将ax的值放入SS:SP指向的内存单元
栈为空时,SS: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=0010H。
当栈为空时,栈中没有元素,也就不存在栈顶元素,所以SS:SP只能够指向栈的最底部单元下面的单元,即栈最底部的字单元的偏移地址+2.
pop指令执行过程
- 将SS:SP指向的内存单元的值放入ax
- SP=SP+2
执行指令后原栈顶的那个数据依旧存在于那个内存单元,只是它不在属于栈了。当执行push之后。它将会被覆盖掉。
栈顶超界问题
当栈满的时候Push以及栈空的时候pop都会发生栈顶超界问题。
而且8086CPU不保证栈的操作不会超界,即8086CPU只知道栈顶的位置。
所以只能使用的时候进行注意了!
8086CPU的工作机理
只考虑当前的情况:
当前栈顶在何处;
当前要执行的指令是哪一条。
8086CPU只记录栈顶,栈空间的大小我们要自己管理。
栈段
我们自己将一段连续的内存单元当做栈段,仅仅是自己的安排,CPU不会自动的将我们自定义的栈段当做栈空间来使用。我们应当将SS:SP指向我们自定义的栈段。
栈为空时,SS:SP的状态
如果我们将10000H~1FFFFH这段空间当作栈段,初始状态是空的,栈空间大小为64KB,栈最底部的字单元地址为1000:FFFE。
SP原来为FFFEH,加2后SP=0,所以,当栈为空的时候,SS=1000H,SP=0。
一个栈段最大可以设置为多少?
从栈的操作指令来看,push、pop只能够修改SP的值,即只能修改偏移地址。
故栈顶的变化范围就是0-FFFFH,从栈空时候的SP=0,一直压栈,直到栈满时SP=0。
所以一个栈段的容量最大为64k,2的16次方。
段的综述
我们可以自由的将一段内存定义为一个段,随意的存放数据、代码或者当做栈来使用。但是若要是让CPU来按照我们的安排,就要把我们定义的段的段地址放入对应的CS、DS、SS,将偏移地址放入对应的地址寄存器,这样才可以使用。
不管我们怎么安排,CPU把某段内存当做代码段,就是因为我们让CS:IP指向了那里。
一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么也不是。
关键在于CPU中寄存器的设置,即:CS、IP、SS、SP、DS的指向。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!