四十四、桟
一、8086内存地址表
起始地址 | 结束地址 | 大小 | 作用 |
---|---|---|---|
0x00000 | 0x003FF | 1KB | 中断向量表 |
0x00400 | 0x004FF | 256B | BIOS数据区 |
0x00500 | 0x07BFF | 30464B约30KB | 可用区域 |
0x07C00 | 0x07DFF | 512B | MBR被BIOS加载到此处,共512个字节 |
0x07E00 | 0x9FBFF | 622080B约608KB | 可用区域 |
0x9FC00 | 0x9FFFF | 1KB | 拓展BIOS数据区 |
0xA0000 | 0xAFFFF | 64KB | 用于彩色显示适配器 |
0xB0000 | 0xB7FFF | 32KB | 用于黑白显示适配器 |
0xB8000 | 0xBFFFF | 32KB | 用于文本模式显示适配器 |
0xC0000 | 0xC7FFF | 32KB | 显示适配器BIOS |
0xC8000 | 0xEFFFF | 160KB | 映射硬件适配器的ROM或内存映射式I/O |
0xF0000 | 0xFFFEF | 64KB-16B | 系统BIOS范围是0xF0000~0xFFFFF共64KB,为了说明入口地址,将最上面的16个字节从此处去掉了,所以此处终止地址为0xFFFEF |
0xFFFF0 | 0xFFFFF | 16B | BIOS入口地址。 此处16个字节的内容是跳转指令:jmp0xF000:E05B |
二、写代码 - 根据可用区域使用桟
从上表可以看出,0x00500 - 0x07BFF
这个可用区域比较大,我们就选这一段,作为桟的位置
我们设置
- 桟段地址:
0x0000
, - 偏移地址:
0xFFFF
因为“栈”这块内存需要经常使用,8086计算机工程师为了让我们更方便的管理“栈”这段内存。
为我们设计提供了“三个”专门负责管理“栈”的寄存器。
SS=Stack Segment
栈段寄存器SP=Stack Pointer
栈顶指针寄存器BP=Base Pointer
栈底指针寄存器
;桟定义到0x0FFFF
mov ax, 0x0000
mov ss, ax
;桟底 ss:bp 合成20位内存地址:0x0FFFF
mov bp, 0xFFFF
;栈顶 ss:sp 合成20位内存地址:0x0FFFF
mov sp, 0xFFFF
;寄存器里存一些数据
mov ax, 0x1234
mov bx, 0x2345
mov cx, 0x3456
mov dx, 0x4567
;桟是数据临时的“中转站”
push ax
push bx
push cx
push dx
;出栈,先进后出
pop dx ;出栈后存到dx
pop cx
pop bx
pop ax
End:
jmp near End
times 510 - ($ -$$) db 0x00
dw 0xAA55 ; 相当于 db 0x55,0xAA
push ax
中的 push
指令相当于做了如下工作:
sub sp, 2
mov word[ss:sp], ax
pop ax
中的 pop
指令相当于做了如下工作:
mov dx, word[ss:sp]
add sp, 2
三、运行结果查看
桟:先进后出,后进先出
观察运行结果,桟底在内存地址高位,栈顶在内存地址低位
每次运行 push
指令,栈顶 sp
都会减 2
虽然出栈的时候我们取出数据,但是桟内存地址里面的数据其实还在,只是桟指针地址已经指向下一个桟地址了
不要把栈想象的有多神秘,就是用 ss,sp,bp
,以及 push
和 pop
指令,管理控制读写的一块内存区域而已。
一般我们要把一些数据临时放到某个内存的时候,就会考虑放到“栈”里面
四、可以自己模拟桟
如果没有SS段寄存器,也没有SP和BP寄存器,也没有push和pop这些汇编指令,就用我们之前学过的知识,我们自己也可以模拟出一个栈来实现。
我们使用:
ds
作为栈段。si
寄存器作为栈底。di
寄存器作为栈顶。
如果要用寄存器来提供偏移地址,只能使用BX、SI、DI、BP
。