1. 程式人生 > 實用技巧 >poj138——建立雷達,貪心,求線段交集

poj138——建立雷達,貪心,求線段交集

一、實驗結論

1.實驗任務1

使用任意文字編輯器,錄入彙編源程式task1.asm,如下:

 1 assume cs:code, ds:data
 2 data segment
 3     db 'Nuist'
 4     db 5 dup(2)
 5 data ends
 6 code segment
 7 start:
 8     mov ax, data
 9     mov ds, ax
10     mov ax, 0b800H
11     mov es, ax
12     mov cx, 5
13     mov si, 0
14     mov di, 0f00h
15 s:  mov
al, [si] 16 and al, 0dfh 17 mov es:[di], al 18 mov al, [5+si] 19 mov es:[di+1], al 20 inc si 21 add di, 2 22 loop s 23 mov ah, 4ch 24 int 21h 25 code ends 26 end start

使用masm、link對task1.asm進行彙編、連結,得到可執行檔案task1.exe,執行效果如下圖所示:

使用debug工具對程式進行除錯,執行到程式返回前,即line23之前,觀察的結果如下圖所示:

修改line4裡5個位元組單元的值,重新彙編、連結、執行,觀察的結果如下圖所示:

1 db 5 dup(2)
2 --> 改成:
3 db 2,3,4,5,6

問題:基於觀察,分析、猜測這裡的數值作用是什麼?

答:為了便於描述我把原始碼中的資料段分成兩個小的資料段一個是①db 'Nuist',另外一個是②db 2,3,4,5,6。從程式碼的一次迴圈所完成功能來看,首先是將

資料段①中的第一個位元組資料也即'N'取出,然後讓'N'與0dfh做按位與操作,其目的是讓所有的小寫字元全部轉換為大寫字元,而對大寫字元無影響。接下來

將轉換為大寫字元的'N'寫入一個位元組到視訊記憶體b8f0h:0的地址空間,之後立馬取出資料段②的第一個位元組資料(即2)寫入一個位元組到視訊記憶體b8f0h:1的地址空間中,

最後進入到下一次迴圈。從上一個實驗二我們已經知道了視訊記憶體空間是以何種方式組織的:高位位元組儲存的是字元的顏色,低位位元組儲存的是字元的二進位制表示。

所以資料段①的作用即為儲存所有的可顯示字元ASCII碼的二進位制表示,資料段②的作用即為儲存對應各個字元的顏色資訊。

2.實驗任務2
實驗任務:已知資料段data中定義位元組資料如下:

1 data segments
2     db 23, 50, 66, 71, 35
3 data ends

編寫程式,在螢幕上以十進位制整數形式列印輸出這5個兩位數

解答:使用任意文字編輯器,錄入彙編源程式task2.asm,內容如下:

 1 ;編寫程式,在螢幕上以十進位制整數形式列印輸出這5個兩位數。
 2 ;48為'0',解決辦法or 110000,or 30
 3 assume cs:code, ds:data, ss:stack
 4 data segment
 5 db 23, 50, 66, 71, 35
 6 data ends;0~fh全部分配給他了
 7 stack segment
 8 db 16 dup(0)
 9 stack ends;10~1f全部分配給它了
10 code segment
11 start:
12     mov ax, data
13     mov ds, ax
14     mov ax, stack
15     mov ss, ax
16     mov sp, 10h
17     mov si, 0;間接定址
18     mov di, 10;除數
19     mov cx, 5;一共迴圈5次
20 s:  mov dx, 0
21     mov ax, dx;dx:ax全部置零
22     mov al, ds:[si];取出資料段的一個位元組資料
23     div di;dx:ax / di然後將商(即十位)放入ax暫存器,將餘數(即個位)放入dx暫存器
24     push dx;先將運算出來的個位用棧暫存,因為我們需要使用dx暫存器列印十位上的字元
25     mov dx, ax;將十位上的數字賦值給dx暫存器
26     or dl, 30h;將十位上的數字轉換為數字字元
27     mov ah, 2
28     int 21h;啟動int 21的2號子功能
29     pop dx;將個位數字取出
30     or dl, 30h;將個位上的數字轉換為數字字元
31     int 21h;啟動int 21的2號子功能
32     inc si;下一個位元組資料
33     loop s
34     mov ah, 4ch
35     int 21h
36 code ends
37 end start

使用masm、link對task1.asm進行彙編、連結,得到可執行檔案task1.exe,執行效果如下圖所示:

使用debug對程式task2.exe做進一步的瞭解,如下圖所示:

程式碼的思路解釋:首先要解決十進位制數字到十進位制數字字元的ASCII值的對映關係,根據ASCII碼錶中數字字元零'0'的ASCII碼值轉換為二進位制表示為110000

而十進位制數字字元'1'的ASCII碼值轉換為二進位制表示為110001,後面字元以此類推,所以我們只需要讓數字1與110000做按位或運算即可獲得對應的數字字元。

關於各行程式碼所完成的功能已經在原始碼中有所體現。

3.實驗任務3

使用任意文字編輯器,錄入彙編源程式task3.asm,如下:

 1 assume cs:code, ds:data, ss:stack
 2 data segment
 3   dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h
 4 data ends
 5 
 6 stack segment
 7   dw 0, 0, 0, 0, 0, 0, 0, 0
 8 stack ends
 9 
10 code segment
11 start:  mov ax,stack
12         mov ss, ax
13         mov sp,16
14         
15         mov ax, data
16         mov ds, ax
17         
18         push ds:[0]
19         push ds:[2]
20         pop ds:[2]
21         pop ds:[0]
22         
23         mov ax,4c00h
24         int 21h
25 
26 code ends
27 end start

回答問題:

①CPU執行程式,程式返回前,data資料段中的資料為多少?

答:從源程式程式碼來看,此程式碼所完成的功能:將data資料段的第一個字資料和第二個字資料自己給自己賦值,其他資料保持不變,所以data資料段中的資料為:

  0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h

利用debug除錯task3.exe,然後使用d命令檢視程式退出之前data段的資料是否和理論分析一致:

②CPU執行程式,程式返回前,根據上圖顯示,cs=0CCDH,ss=0CCCH,ds=0CCBH

③設程式載入後,code段的段地址為X,則data段的段地址為X - 2H,satck段的段地址為X - 1H
4.實驗任務4

使用任意文字編輯器,錄入彙編源程式task4.asm,如下:

 1 assume cs:code, ds:data, ss:stack
 2 data segment
 3   dw 0123h, 0456h
 4 data ends
 5 
 6 stack segment
 7   dw 0, 0
 8 stack ends
 9 
10 code segment
11 start:  mov ax,stack
12         mov ss, ax
13         mov sp,16
14         
15         mov ax, data
16         mov ds, ax
17         
18         push ds:[0]
19         push ds:[2]
20         pop ds:[2]
21         pop ds:[0]
22         
23         mov ax,4c00h
24         int 21h
25 code ends
26 end start

回答問題:

①CPU執行程式,程式返回前,data段中的資料為多少?

答:從源程式程式碼來看,此程式碼所完成的功能:將data資料段的第一個字資料和第二個字資料自己給自己賦值,其他資料保持不變,所以data資料段中的資料為:

  0123h, 0456h, 0h,0h,0h,0h,0h,0h

利用debug除錯task4.exe,然後使用d命令檢視程式退出之前data段的資料是否和理論分析一致:

②CPU執行程式,程式返回前,根據上圖顯示,cs=0CCDH,ss=0CCCH,ds=0CCBH

③設程式載入後,code段的段地址為X,則data段的段地址為X - 2H,satck段的段地址為X - 1H

④對於如下定義的段:

1 name segment
2   ......
3 name segment

如果段中的資料佔N個位元組,則程式載入後,該段實際佔有的空間為 N % 16 == 0? N: (N / 16 + 1) * 16。至於原因:作業系統為程式分配的資料單元最小為16個位元組。

5.實驗任務5

使用任意文字編輯器,錄入彙編源程式task5.asm,如下:

 1 assume cs:code, ds:data, ss:stack
 2 code segment
 3 start:  mov ax,stack
 4         mov ss, ax
 5         mov sp,16
 6         
 7         mov ax, data
 8         mov ds, ax
 9         
10         push ds:[0]
11         push ds:[2]
12         pop ds:[2]
13         pop ds:[0]
14         
15         mov ax,4c00h
16         int 21h
17 
18 code ends
19 data segment
20   dw 0123h, 0456h
21 data ends
22 stack segment
23   dw 0,0
24 stack ends
25 end start

回答問題:

①CPU執行程式,程式返回前,data段中的資料為多少?

答:從源程式程式碼來看,此程式碼所完成的功能:將data資料段的第一個字資料和第二個字資料自己給自己賦值,其他資料保持不變,所以data資料段中的資料為:

  0123h, 0456h, 0h,0h,0h,0h,0h,0h

利用debug除錯task5.exe,然後使用d命令檢視程式退出之前data段的資料是否和理論分析一致:

②CPU執行程式,程式返回前,根據上圖顯示,cs=0CCBH,ss=0CCFH,ds=0CCEH

③設程式載入後,code段的段地址為X,則data段的段地址為X + 3H,satck段的段地址為X + 4H

6.實驗任務6

實驗任務:如果將實驗任務3、4、5中的最後一條偽指令“end start”改為“end”(也就是說,不指明程式的入口),則哪個程式仍然可以正確執行?請說明理由。

答:如果不顯示地指明程式的入口,那麼只有實驗任務5的程式碼仍會正確執行。究其原因,Debug總是把我們編寫的彙編程式碼(已經彙編成機器碼)順序地載入進

記憶體並將CS:IP指向我們編寫程式碼段的入口,當然如果沒有顯示地指明程式入口,預設會指向所編寫彙編程式碼的第一行指令。正是由於此原因,實驗任務3、4中代

碼的第一行指令並不是屬於程式碼段,而是屬於資料段,但是由於沒有明確地指明程式入口,致使CPU誤把資料段的內容作為程式碼來執行了,所以導致程式無法執行

我們所編寫的程式碼段。同時,由於實驗任務5的原始碼雖然沒有明確指明程式碼段的實際入口,但是程式碼段始終都放在彙編程式碼的第一行,這樣CPU也能正確執行我

們編寫的程式碼段。為了驗證以上理論分析,下面分別對三個程式進行debug除錯對比,如下圖所示:

7.實驗任務7

實驗任務:編寫code段中的程式碼,將a段和b段中的資料依次相加,將結果存到c段中。

解答:使用任意文字編輯器,錄入彙編源程式task6.asm,內容如下:

 1 assume cs:code
 2 a segment
 3     db 1,2,3,4,5,6,7,8
 4 a ends
 5 b segment
 6     db 1,2,3,4,5,6,7,8
 7 b ends
 8 c segment 
 9     db 8 dup(0)
10 c ends
11 code segment
12 start:
13     mov ax, a
14     mov ds, ax;資料從哪裡來
15     mov bx, 0;間接定址
16     mov si, 10h;資料段b的間接定址
17     mov ax, c
18     mov es, ax;資料到哪裡去
19     mov cx, 8;迴圈8次
20 s:    mov al, ds:[bx];取出資料段a的一個位元組資料
21     add al, ds:[bx+si];取出資料段b的一個位元組資料並與資料段a的位元組資料求和
22     mov es:[bx], al;將求和結果放到資料段c當中
23     inc bx
24     loop s
25     mov ah, 4ch
26     int 21h
27 code ends
28 end start

使用debug對task6.exe進行除錯,測試程式碼是否完成實驗任務要求,如下圖所示:

8.實驗任務8

實驗任務:編寫code段中的程式碼,用push指令將a段中的前8個字型資料,逆序存放到b段中。

解答:使用任意文字編輯器,錄入彙編源程式task7.asm,內容如下:

 1 assume cs:code
 2 a segment
 3     dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
 4 a ends;一共32個位元組0~1fh
 5 b segment
 6     dw 8 dup(0)
 7 b ends;一共16個位元組20~2fh
 8 code segment
 9 start: 
10     mov ax, a
11     mov ds, ax;資料從哪裡來
12     mov ax, b
13     mov es, ax;資料到哪裡去
14     mov bx, 0;資料段a間接定址
15     mov si, 0eh;資料段b間接定址
16     mov cx, 8;迴圈執行次數
17 s:    push ds:[bx];將資料段a的一個字資料入棧
18     pop es:[si];將剛入棧的字資料出棧到資料段b
19     add bx, 2
20     sub si, 2
21     loop s
22     mov ah, 4ch
23     int 21h
24 code ends
25 end start

使用debug對task7.exe進行除錯,測試程式碼是否完成實驗任務要求,如下圖所示: