本章目标:
- 学习栈,了解处理器为了访问栈提供了怎样的支持
- 总结INTEL8086处理器的寻址方式
- 学习新的指令,or、and、push和pop
- 学习bochs调试程序时查看栈的方法
7.2 代码清单
asm-7-1.pdf
7.3 显示字符串
解读10-28行代码,即显示message字符串的功能
7.4 1到100的累计和
解读31到37行的代码,即通过CX和jns指令来循环执行,获取累计和
7.5 累加和各个数位的分解和显示
7.5.1 栈和栈段的初始化
- 栈也是一个内存段,叫栈段(Stack Segment),由寄存器SS指向
- 规划内存布局,同时将寄存器SS和栈指针SP置0
7.5.2 or,and,push指令
- or指令,执行“或”操作,结果存于目的操作数中
- and指令,执行“与”操作,结果存于目的操作数中
- push指令,将寄存器或者内存地址的内容压入栈。在16位处理器上,push指令的操作数可以是16位的寄存器和内存单元
- 例子:
push ax
push word [label_a]
push al     ;非法指令,16位处理器,只能压入字
- 在执行push指令的时候,首先将栈指针寄存器SP的内容减去操作数的长度(以字节为单位的长度,在16位处理器上是2);然后将要压入栈的数据存放到逻辑地址SS:SP所指向的内存位置。由于SP初始化的时候为0,减去之后,SS:SP指向0xFFFE;此时,栈的执行是从高地址往低地址,而代码段CS的执行从低地址向高地址移动,这样就解决了栈段和代码段分离的问题。
7.5.3 pop指令
- pop指令,弹栈功能。将逻辑地址SS:SP处的一个字弹出到寄存器或内存位置中,然后将SP的内容加上操作数的字长(2)
- 例子:
pop ax
pop word [lable_a]
7.5.4 进一步认识栈
- push指令的详细流程
;push ax 可以用以下指令取代
sub sp, 2
mov bx, sp
mov [ss:bx], ax
- pop指令的详细流程
; pop ax 可以用以下指令取代
mov bx, sp
mov ax, [ss:bx]
add sp, 2
- 使用栈的注意事项
- 注意保持栈的平衡
- 充分估计栈的空间,防止破坏有用的数据
- 尽管不能完全阻止程序中的错误,但是通过将栈定义到一个单独的64KB段,可以使错误仅局限于栈
7.6 程序的编译和运行
7.7 8086处理器的寻址方式
寻址方式:即处理器如何找到被操作的数,以及如何找到存放数据的地方
7.7.1 寄存器寻址
从寄存器取得操作的数
mov ax, cx
add bx, 0xf000
inc dx
7.7.2 立即寻址
指令的操作数是一个立即数
add bx, 0xf000
mov dx, lable_a
7.7.3 内存寻址
1、直接寻址
所谓直接寻址,即使用该寻址方式的操作数是一个偏移地址,而且给出了改偏移地址的具体数值
mov ax, [0x5c0f]
mov word [0x0230], 0x5000
xor byte [es:lable_b], 0x05    ;标号是数值的等价形式
2、基址寻址
所谓基址寻址,即在指令的地址部分使用基址寄存器BX或BP来提供偏移地址,例如:
- BX作为基址寄存器
mov [bx], dx
add byte [bx], 0x55
好处是,可以用来进行批量加一的任务
buffer dw 0x20, 0x100, 0x0f, 0x300, 0xff00
mov bx, buffer
mov cx, 4
lpinc:
inc word [bx]
add dx, 2
loop lpinc
- BP作为基址寄存器
mov ax, [bp]
;将SS:BP处的一个字传送到寄存器AX中
使用BP的作用是为了能够随意访问栈中的内容。一个应用就是函数调用时,访问那些被压在栈底的参数
3、变址寻址
类似于基址寻址,唯一不同之处在于,这种方式使用的是变址寄存器(或称索引寄存器)SI和DI
mov [si], dx
add ax, [di]
xor word [si], 0x8000
;处理器会访问由段寄存器DS指向的数据段,偏移地址由寄存器SI和DI提供
4、基址变址寻址
mov ax, [bx+si]
add word [bx+di], 0x3000