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


實驗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機器的內存,在內存地址C0000FFFFF之間為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 8007 3F,恰好是IPCS的值,而這個CS:IP,即073f:0180對應了棧初始化的下一行指令:mov ax, 2010

查閱網上相關討論得知,可能是由於這段匯編未在開始時通過偽指令定義棧段和數據段,因此在初始化棧的時候系統認為這是一次中斷,而debug中會暫時借用主程序的棧存放CSIPFlag的值,因此在mov ss, axmov sp, 30被執行后,系統中斷,將下一條指令mov ax, 2010的邏輯地址,也就是CS:IP的值入棧,然后執行棧初始化。至於A3 01有人說是Flag的值,一個標記,具體是什么標記尚不清楚。
此外,另一篇博客指出,其實棧中除了明顯的CSIPFlag等值,還總是保存AXBP兩個寄存器的內容。棧中依次存放了:AXBPIPCSeflags的值。一個解釋是:由於把此處的位置當做棧了,而-t命令產生中斷,所以就將 標識寄存器CSIP入棧保存。

其實這些討論也很模糊,沒有說到細節,有待進一步研究棧初始化過程中究竟發生了什么事。

相關討論:

https://zhidao.baidu.com/question/1667892790408757387.html

https://tieba.baidu.com/p/5459150294

http://www.cppblog.com/Tim/archive/2012/06/13/178666.html

當棧初始化完成后,后面正常的壓棧操作依然從棧底開始進行,直接無視了之前壓入棧中的IPCSFlag

然而之前存儲的IPCSFlag的值卻仍然會隨着壓棧操作向棧頂方向移動。有意思的是,這三個值隨着壓棧的操作依次往棧頂方向移動,而且IP的值也在一直改變,始終為下一條待執行指令的值,和IP寄存器同步。前面AX, BX

只有神秘的A3 01一直沒有變過。

很有意思,但是不知道為什么棧中會一直留着CSIPFlag的值,也不知道為什么會一直更新。感覺網上的討論也有些問題。

實驗任務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看到DSCSDS + 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開始的地址空間中

實驗總結

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM