这部分掌握的还可以,略。
使用d命令,查看 FFF0:0 ~ FFF0:FF 之间的数据,可以看到有一个01/01/92,猜测是1992年1月1日。
使用d命令进一步查看,在FFF0:F5 ~ FFF0:FC区间为日期的内存地址。两个2F对应”/“
现将日期修改为1999年12月12日:31 31 2F 31 31 2F 39 39
然而发现日期并没有被修改成功。
原因为:8086机器的内存,在内存地址C0000—FFFFF之间为ROM区域,而日期存在ROM区域,ROM区域无法进行修改。
执行第一个命令:-e b800:0 03 04 03 04 03 04 03 04 03 04
后,可以看到顶部出现了五个红心
执行第二个命令:-f b800:0f00 0f9f 03 04
,可以看到屏幕底部出现了一排红心
尝试向其他字节填充指令:
如输入指令:-f b800:0 0f00 04 05
,则可以看到屏幕被紫色菱形充满
如输入命令:-f b800:10 0f9f 08 09
,则可以看淡满屏蓝色和圆点
8086的显存空间的地址是B8000H~BFFFFH
,共32KB空间,为80x25彩色字符模式的显示缓冲区。向这个地址空间写入数据,写入的内容将立即出现在显示器上。
栈顶逻辑地址:0020:30
栈顶物理地址:00230H
观察并记录栈顶偏移地址的寄存器sp值的变化情况
-a mov ax, 20 mov ds, ax mov ss, ax mov sp, 30 push [0] ; 执行后,寄存器(sp) = _002E_ push [2] ; 执行后,寄存器(sp) = _002C_ push [4] ; 执行后,寄存器(sp) = _002A_ push [6] ; 执行后,寄存器(sp) = _0028_ pop [6] ; 执行后,寄存器(sp) = _002A_ pop [4] ; 执行后,寄存器(sp) = _002C_ pop [2] ; 执行后,寄存器(sp) = _002E_ pop [0] ; 执行后,寄存器(sp) = _0030_
执行指令 | SP指针 |
---|---|
push [0] | 002E |
push [2] | 002C |
push [4] | 002A |
push [6] | 0028 |
pop [6] | 002A |
pop [4] | 002C |
pop [2] | 002E |
pop [0] | 0030 |
push[6]
执行结束,查看d 20:20 2f
pop[0]
执行结束,查看 d 20:0 7
可以看到并没有任何变化
如果将073F:011A~073F:0126改为以下顺序:
073F:011A pop [0] 073F:011E pop [2] 073F:0122 pop [4] 073F:0126 pop [6]
可以看到数据发生了变化
mov sp, 30
在执行完mov ss, ax
后立刻被执行了,可以看到mov ss, ax
执行后SP变为了30,下一条指令变成了mov ax, 2010
mov sp会和mov ss,ax一起执行,这是因为这是为了确保对SS段寄存器和栈指针的修改不被破坏。(在此期间CPU不会响应其他中断)
栈初始化时,当SS
指针被修改后,栈空间的值也发生了变化。
可以看到从0020:2A ~ 0020:2D
被填充了01 80和07 3F,恰好是IP和CS的值,而这个CS:IP,即073f:0180
对应了栈初始化的下一行指令:mov ax, 2010
查阅网上相关讨论得知,可能是由于这段汇编未在开始时通过伪指令定义栈段和数据段,因此在初始化栈的时候系统认为这是一次中断,而debug中会暂时借用主程序的栈存放CS、IP和Flag的值,因此在mov ss, ax和mov sp, 30被执行后,系统中断,将下一条指令
mov ax, 2010
的逻辑地址,也就是CS:IP的值入栈,然后执行栈初始化。至于A3 01
有人说是Flag的值,一个标记,具体是什么标记尚不清楚。其实这些讨论也很模糊,没有说到细节,有待进一步研究栈初始化过程中究竟发生了什么事。
相关讨论:
https://zhidao.baidu.com/question/1667892790408757387.html
https://tieba.baidu.com/p/5459150294
当栈初始化完成后,后面正常的压栈操作依然从栈底开始进行,直接无视了之前压入栈中的IP、CS、Flag。
然而之前存储的IP、CS和Flag的值却仍然会随着压栈操作向栈顶方向移动。有意思的是,这三个值随着压栈的操作依次往栈顶方向移动,而且IP的值也在一直改变,始终为下一条待执行指令的值,和IP寄存器同步。
只有神秘的A3 01
一直没有变过。
很有意思,但是不知道为什么栈中会一直留着CS、IP和Flag的值,也不知道为什么会一直更新。感觉网上的讨论也有些问题。
程序源码:
assume cs:code code segment start: mov cx, 10 mov dl, '0' s: mov ah, 2 int 21h add dl, 1 loop s mov ah, 4ch int 21h code ends end start
编译、链接、执行过程
使用debug调试:
首先使用-r
看到DS
和CS
,DS + 100H
正好是CS
的值,100H也就是256字节,验证了PSP段大小的确是256B,且PSP段和程序段紧邻。
书上说:
PSP区和程序区虽然物理地址连续,却有不同的段地址。
在这里可以得到验证
查看DS
处的内容:
可以看到的确是CD 20
,反汇编指令是INT 20
,这条指令指程序终止,应该就是中断当前程序,然后下一条CALL
指令转移至程序段运行(猜测)
程序代码:
assume cs:code code segment mov ax, __cs__ mov ds, ax mov ax, 0020h mov es, ax mov bx, 0 mov cx, __17h__ s: mov al, [bx] mov es:[bx], al inc bx loop s mov ax, 4c00h int 21h code ends end
(1)第一空:cs
(2)第二空:17h
原因:由于是复制当前程序,当前程序的程序段地址存储在CS
中,因此将CS
中的数据移至DS
寄存器作为数据段,所以第一空填cs。而第二空17h则是通过先编译程序后观察程序的大小决定,如下图:
可以看到程序到mov ax, 4c00h
指令之前共占用了17h个字节,因此需要循环17h次。
使用debug调试程序:-g=0 17
可以看到程序已经正确复制到了0:200
开始的地址空间中