實驗 5 編寫、調試具有多個段的程序
一、實驗目的
1. 理解和掌握將數據、代碼、棧放入不同段的程序的編寫和調試
2. 理解具有多個段的匯編源程序對應的目標程序執行時,內存分配方式
二、實驗準備
1. 結合第 6 章教材和課件,復習第 6 章內容
2. 復習第 3 章「棧」的知識
三、實驗內容
實驗任務(1)
下載課程公郵中的程序框架放入,masm.exe,link.exe同文件夾下,用DS BOX掛載到masm文件夾後
使用之前寫好的process.bat文件簡化編譯,連接,執行操作。
順利執行,下面對ex5_1.exe debug。
使用r命令查看各寄存器的值,下面我們要精確反匯編程序段,首先通過r命令可以看出cx=0042,
即這段程序所占的字節數是42h,但這還包括數據段和棧段,數據段有8個數據,16個字節,即
10h,棧段也是16個字節,即10h。所以代碼段長度為42-20=22h,CS:IP = 076C:0000,所以若要精確反匯編
,應該是u 0000 0021(註:代碼段,棧段,數據段均是從0開始的)。成功反匯編代碼段。
題目要求的是程序返回前,即 mov ax,4c00 int 21前,根據反匯編結果可知,因執行到CS:001d前,使用
g命令達到這一效果。
已經可以看出CPU執行程序,程序返回前,cs=076c,ss=076b,ds=076a.
接下來需要查看數據段,已知數據段長16個字節,使用d命令查看內存中的數據 d 0 f(註:代碼段,棧段,數據段均是從0開始的)
可以看出,程序返回前的數據段並沒有改變(讀數據時註意是小端法存儲的)。
使用g命令執行完程序,程序加載後,可以看出DS = CS-2,SS=CS-1;
根據實驗結果完成了書中填空。
實驗任務(2)
前期步驟同(1)
同實驗(1),首先通過r命令可以看出cx=0042,即這段程序所占的字節數是42h,但這還包括數據段和棧段,數據段有2個數據,4個字節,棧段也是2個字節。
所以代碼段長度為42-8=34h,CS:IP = 076C:0000,所以若要精確反匯編
,應該是u 0000 0033(註:代碼段,棧段,數據段均是從0開始的)。但這裏我卻並沒有做到成功反匯編,顯然我們所給反匯編範圍大了
通過查看源代碼,給出猜測,雖然棧段和數據段都只給出了4個字節,但從第13行代碼看出
,這裏設sp = 16,棧頂設為了16,也就是說這裏的棧仍然是16個字節的,盡管沒有填滿,所以情況應該和
實驗(1)是一樣的,當然這只是我的猜測
精確反匯編的結果與實驗(1)一樣
題目要求的是程序返回前,即 mov ax,4c00 int 21前,根據反匯編結果可知,因執行到CS:001d前,使用
g命令達到這一效果。
已經可以看出CPU執行程序,程序返回前,cs=076c,ss=076b,ds=076a.
接下來需要查看數據段,已知數據段長4個字節,使用d命令查看內存中的數據 d 0 3(註:代碼段,棧段,數據段均是從0開始的)
可以看出,程序返回前的數據段並沒有改變(讀數據時註意是小端法存儲的)。
使用g命令執行完程序,程序加載後,可以看出DS = CS-2,SS=CS-1;
這裏的情況和實驗(1)是一樣的
考慮對於如下定義的段:
name segment
...
name ends
通過查閱資料得知
如果段中數據占N個字節,則程序加載後,該段實際占有的空間為 [(N+15)/16]*16。
數據段都是以16個字節對齊,不足16字節按16字節算,這也解釋了對於實驗任務(2)我的
疑問。
根據實驗結果完成書中填空
實驗任務(3)
與實驗任務(1)(2)相同,前面的步驟在這裏就省略截圖分析了,直接從debug後開始
這裏的精確反匯編又出現了問題,根據之前的實驗總結,應該是CX = 44-10-10=24h,
所以應該是 u 0 23進行精確反匯編,但這裏卻還是應該 u 0 21。原因不得而知。
修改後精確反匯編
已經可以看出CPU執行程序,程序返回前,cs=076a,ss=076e,ds=076d.
接下來需要查看數據段,已知數據段長4個字節,使用d命令查看內存中的數據 d 0 3(註:代碼段,棧段,數據段均是從0開始的)
可以看出,程序返回前的數據段並沒有改變(讀數據時註意是小端法存儲的)。
使用g命令執行完程序,程序加載後,可以看出DS = CS+3,SS=CS+4;
根據實驗結果完成書中填空
實驗任務(4)
如果將(1),(2),(3)題中的最後一條偽指令“end start”
改為“end”(也就是說,不指明程序的入口個)
,則哪個程序仍然可以正確執行?請說明原因。
對三個程序內容進行修改編譯連接執行後
對第一個程序的反匯編結果,可以發現該程序已經沒有辦法正確執行
程序2也是無法正確執行
程序3可以正確執行
因為如果沒有end start就會默認以IP=0開始執行,而不是從start開始執行。
而實驗內容(3)的data和stack都在code之後,所以IP本來就為0,可以正確執行。
實驗任務(5)
(1) 匯編程序源代碼
補全代碼如下:
分析:編寫code代碼,將a段b段中的數據依次相加,將結果存在c段中。
bx用於偏移量,初始置顯然為0,dx為求和寄存器初始值也是0,cx用於設置循環次數,這裏有a,b中均有8個字
,所以循環次數也就是8次。
循環體部分:每次將a段中和b段中內容依次加到寄存器dx中,最後將結果存到c段中。
這裏需要註意,循環體開頭部分每次都要將用於求和的寄存器bx置為0,否則上次的結果會接著累加。
偏移量bx每次增加一次,大體步驟就是這樣,具體細節在這裏就不做過多的闡述。
(2) 在 debug 中調試程序截圖,截圖中包括如下信息:
① 在實現數據相加前,邏輯段 c 的 8 個字節
進入debug,然後查看寄存器,精確反匯編(CX-10h-10h-10h=29h),u 0 28
根據精確反匯編結果,執行到循環體外,使用d命令查看數據段內容,發現並沒有做到預期,
但查看棧段內容時,發現第二行到第四行顯示的內存符合預期,原因不得而知。
② 執行完實現加運算的代碼後,邏輯段 c 的 8 個字節
使用g命令執行完成後,發現用d命令查看數據段內存內容仍然不符合預期,但棧段內存內容
符合,第四行確實是前兩行相加的結果。
根據①和②的調試,證實了程序確實正確的實現數據相加。
實驗任務(6)
(1) 匯編程序源代碼
補全代碼如下:
分析:編寫code段中的代碼,用push指令將a段中的前8個字型數據,逆序存儲b段中。
需要逆序存儲,自然的便想到了棧段,這裏需要設一個棧段,需要將b段前8個字數據逆序存儲,
8個字數據即16個字節,棧頂SP = 16 =10h,棧底為SS = SP+1.
這裏只要設置8次循環,將a段中前8個字型數據push到棧中,即實現了題目要求。
(2) 在 debug 中調試程序截圖,截圖中包括如下信息:
進入debug,使用r命令進行查看,精確反匯編(CX-20h-10h=1fh)u 0 1e
成功精確反匯編。
① 在 push 操作執行前,查看邏輯段 b 的 8 個字單元信息截圖
根據反匯編結果,使用g命令執行到push操作前,用d命令查看內存中內容,長度為a段的
32(20h)個字節加上b段16(10h)個字節,d ds:0 29.
可以看出b段8個字全是0.
② 執行 push 操作,然後再次查看邏輯段 b 的 8 個子單元信息截圖
使用g命令執行完成後,用d命令查看,發現b的8個字單元為a段前8個字節的逆序.
根據①和②的調試,驗證程序確實正確的實現題目要求。
五、總結與體會
1.通過此次實驗理解和掌握將數據、代碼、棧放入不同段的程序的編寫和調試
理解具有多個段的匯編源程序對應的目標程序執行時,內存分配方式。
2.我們開始逐漸進入到匯編編程中,匯編也並不是很枯燥的,在實驗過程中只有不斷的探索嘗試才能真正
體會匯編的樂趣。
實驗 5 編寫、調試具有多個段的程序