16位寄存器来存储一个字,高8位存放高位字节,低8位存放低位字节。 ,(一个单元存放一个字节),则一个字要用两个地址连续的内存单元来存放。
eg:从地址0存放20000,,20000(4E20H),要 0 1 两个单元才能存放,0 存放低位 20 ,1 存放高位4E。
//接着存放 18 (12H),高位不足补 0 ,低位 12 。
区分 0 地址单元和 0 地址字单元。
DS:存放数据的段地址。
eg:读取 10000H 单元的内容
mov bx , 1000H mov ds , bx mov al , [0] 将10000H(1000:0)中的数据读到 al 中。 |
mov al , [0] 表示把内存单元地址读入寄存器al。[...]表示操作对象是一个内存单元,0表示内存单元的偏移地址,在指令执行时8086CPU自动取ds中的数据作为段地址。段地址*16+偏移地址一起放入al。 * DS 是一个段寄存器,mov不能把数据直接放入段寄存器,所以要先放到数据寄存器 BX 。 |
将数据从寄存器送入内存单元 | mov bx , 1000H mov ds , bx mov [0] , al |
访问数据段中的数据,编程中我们可以定义一段内存空间来存放数据,eg:将123B0H~123BAH 的内存单元定义为数据段。现在累加这个数据段中的前三个单元中的数据。 我事先在1000:0里存放了01 02 03其他全为0;一个数字占8位,寄存器是16位,为了统一就必须用al,低8位相加。 |
mov ax , 1000 mov ds , ax ; 将1000H送入ds中,作为数据段的段地址 mov al , 0 ;用 al 存放累加结果 add al , [0] ;将数据段第一个单元中的数值加到al中 add al , [1] ;将数据段第二个单元中的数值加到al中 add al , [2] ;将数据段第三个单元中的数值加到al中 |
*** -d 查看内存,一个数字表示4位,一般都是两个数字紧挨在一起,显示的是16个8位,一行可以显示128位。在进行加法运算的时候如果使用ax寄存器,由于它是16位的,cpu自动对齐,会把1000:0000和1000:0001的一共16位来相加放到ax里面,结果就会是0201,最终结果会是0506。我们只想每次加8位,所以要用低8位寄存器al,ax=ah+al;这样的话最终结果就是ax=0006。如果非要用ax,那么指令会是add ax , [0] ;add ax , [2] ;add ax , [4] ;1000:0 中的数据要是01 00 02 00 03 00;
CPU 提供栈机制
PUSH 和 POP ,push ax 表示将寄存器 ax 中的数据送入栈中,pop ax 表示从栈顶取出数据送入 ax 。8086CPU 的入栈和出栈操作都是以字位单位进行的。注意,字型数据都是用两个单元存放的,高地址、单元存放高 8 位,低地址单元存放低 8 位。
CPU 要取的当前执行的指令位置是靠 CS:IP 来给出,同样8086CPU会把一段当做栈空间,为了知道栈顶位置,8086CPU用两个段寄存器 SS 和 SP ,栈顶的段地址存放在 SS 中,偏移地址存放在 SP 中,任意时刻,SS:SP 指向栈顶元素。执行 push 和 pop 指令的时候,CPU 从 SS 和 SP 中得到栈顶地址。
push ax
1、sp=sp-2 ,ss:sp 指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;
2、将 ax 中的内容送入 ss:sp 指向的内存单元处,ss:sp 此时指向新栈顶。
// 栈向下生长
栈空间有限,如有发生越界会污染其他数据。
8086CPU 不存在指示栈上限和栈下限的寄存器;
push pop{ 寄存器、段寄存器、内存单元 } eg:如果我们将 10000H~1000FH 这段空间当作栈,初始状态是空的,此时 SS=1000H,SP=0010H 因为空栈,SS:SP 指向1000F 的上一个单元就是1000:0010 ;
将 10000H~1000FH 这段空间当作栈,初始状态是空的,设置 AX=001AH , BX=001BH ; 将AX、BX中的数据入栈;然后将AX、BX清零,从栈中恢复AX、BX原来的内容。 |
mov ax , 1000 mov ss , ax ; 设置栈的段地址(不能把数据直接送入段寄存器) mov sp , 0010 ;设置栈顶的偏移地址 mov ax , 001A mov bx , 001B push ax push bx sub ax , ax ; 可以用mov ax , 0指令占三个字节 sub机器码为两个字节 pop bx pop ax |
在 10000H 处写入字型数据 2266H | mov ax , 1000 mov ds , ax mov ax , 2266 mov [0] , ax |
自己定义一段空间(必须是16的倍数),设置SS:SP指向定义的栈段当做栈使用
eg:假设栈段 10000H~1FFFFH (64KB),初始是空的,SS=1000H,SP=0;
因为空栈 SS:SP 指向1000:FFFF 上一个,SP=FFFF,SP+1=0;
段:一个段存放数据,“数据段”DS 一个段存放代码,“代码段”CS 一个段当做栈,“栈段”SS |
debug命令中 -d 命令用段寄存器中的数据为段地址 SA ,列出从 SA:偏移地址开始的内存区间中的数据。
修改栈段寄存器 SS 的指令在用 t 命令查看的时候看不到,它会自动在前一条指令执行后跟着自动执行,这涉及到中断