實驗1 8086匯編指令編碼和調試
實驗任務1

這部分掌握的還可以,略。
實驗任務2
使用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區域無法進行修改。
實驗任務3
執行第一個命令:-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彩色字符模式的顯示緩沖區。向這個地址空間寫入數據,寫入的內容將立即出現在顯示器上。
實驗任務4

問題1:
棧頂邏輯地址: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 |
問題2:
push[6]
執行結束,查看d 20:20 2f

問題3:
pop[0]
執行結束,查看 d 20:0 7
可以看到並沒有任何變化

問題4:
如果將073F:011A
~ 073F:0126
改為以下順序:
073F:011A pop [0]
073F:011E pop [2]
073F:0122 pop [4]
073F:0126 pop [6]
可以看到數據發生了變化

實驗任務5
問題1


mov sp, 30
在執行完mov ss, ax
后立刻被執行了,可以看到mov ss, ax
執行后SP變為了30,下一條指令變成了mov ax, 2010
mov sp, 30
會和mov ss, ax
一起執行,這是因為這是為了確保對SS段寄存器和棧指針的修改不被破壞。(在此期間CPU不會響應其他中斷)
問題2
棧初始化時,當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的值,一個標記,具體是什么標記尚不清楚。
此外,另一篇博客指出,其實棧中除了明顯的CS
、IP
、Flag
等值,還總是保存AX
和BP
兩個寄存器的內容。棧中依次存放了:AX
,BP
,IP
,CS
,eflags
的值。一個解釋是:由於把此處的位置當做棧了,而-t
命令產生中斷,所以就將標識寄存器
、CS
、IP
入棧保存。其實這些討論也很模糊,沒有說到細節,有待進一步研究棧初始化過程中究竟發生了什么事。
相關討論:
https://zhidao.baidu.com/question/1667892790408757387.html

當棧初始化完成后,后面正常的壓棧操作依然從棧底開始進行,直接無視了之前壓入棧中的IP
、CS
、Flag
。
然而之前存儲的IP
、CS
和Flag
的值卻仍然會隨着壓棧操作向棧頂方向移動。有意思的是,這三個值隨着壓棧的操作依次往棧頂方向移動,而且IP的值也在一直改變,始終為下一條待執行指令的值,和IP寄存器同步。前面AX
, BX
只有神秘的A3 01
一直沒有變過。
很有意思,但是不知道為什么棧中會一直留着CS
、IP
和Flag
的值,也不知道為什么會一直更新。感覺網上的討論也有些問題。

實驗任務6
程序源碼:
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
指令轉移至程序段運行(猜測)

實驗任務7
程序代碼:
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
開始的地址空間中

實驗總結
- 8086的工作在實模式下,對內存直接操作,觀察最明顯的是對顯存空間的操作。通過直接改寫顯存地址空間的數據,可以讓屏幕上直接顯示對應內容。
- 用debug調試起來很麻煩,輸錯了一個地方只能重來。但也沒啥更好的工具了。
- 棧空間的使用方面,棧中會始終保存
AX
、BP
、CS
、IP
和Flag
的值,而且一直處在棧頂位置,具體和CPU中斷有關,但是這里無法看到細節內容,需要進一步了解。 - 工作在實模式下盡管操作很方便,但是不利於內存保護。一旦寫入錯誤的位置可能就會導致系統崩潰。保護模式是在實模式的基礎上加了一些數據表,通過這些數據表來查找對應的邏輯段和地址,而無法通過實模式那樣直接使用一個公式計算地址。但是保護模式的表數據結構定義非常麻煩且容易出錯。